精华内容
下载资源
问答
  • AJAX中同步异步区别和使用场景
    2021-03-08 16:39:37

    AJAX中根据async的值不同分为同步(async = false)和异步(async = true)两种执行方式;在W3C的教程中推荐使用异步执行;

    下面来区别一下同步和异步有什么不同:

    异步:在异步模式下,当我们使用AJAX发送完请求后,可能还有代码需要执行。这个时候可能由于种种原因导致服务器还没有响应我们的请求,但是因为我们采用了异步执行方式,所有包含AJAX请求代码的函数中的剩余代码将继续执行。如果我们是将请求结果交由另外一个JS函数去处理的,那么,这个时候就好比两条线程同时执行一样。

    同步:在同步模式下,当我们使用AJAX发送完请求后,后续还有代码需要执行,我们同样将服务器响应交由另一个JS函数去处理,但是这时的代码执行情况是:在服务器没有响应或者处理响应结果的JS函数还没有处理完成return时,包含请求代码的函数的剩余代码是不能够执行的。就好比单线程一样,请求发出后就进入阻塞状态,知道接触阻塞余下的代码才会继续执行。

    如何选择同步还是异步模式?要回答这一问题,我们可以通过下面可能出现的问题来回答:

    我们在发送AJAX请求后,还需要继续处理服务器的响应结果,如果这时我们使用异步请求模式同时未将结果的处理交由另一个JS函数进行处理。这时就有可能发生这种情况:异步请求的响应还没有到达,函数已经执行完了return语句了,这时将导致return的结果为空字符串。

    更多相关内容
  • Log4j 2中记录日志的方式有同步日志异步日志两种方式,其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式。 2.Log4j2中的同步日志 所谓同步日志,即当输出日志时,必须等待日志输出语句执行完毕...

    目录

    1.背景

    2.Log4j2中的同步日志

    3.Log4j2中的异步日志

    3.1 AsyncAppender

    3.2 AsyncLogger

    Disruptor简介

    AsyncLogger

    4.总结


    1.背景

    Log4j 2中记录日志的方式有同步日志和异步日志两种方式,其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式。

    2.Log4j2中的同步日志

    所谓同步日志,即当输出日志时,必须等待日志输出语句执行完毕后,才能执行后面的业务逻辑语句。

    下面通过一个例子来了解Log4j2中的同步日志,并借此来探究整个日志输出过程。

    log4j2.xml配置如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="debug" name="MyApp" packages="">
        <!--全局Filter-->
        <ThresholdFilter level="ALL"/>
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            </Console>
            <RollingFile name="RollingFile" fileName="logs/app.log"
                         filePattern="logs/app-%d{yyyy-MM-dd HH}.log">
                <!--Appender的Filter-->
                <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
                <PatternLayout>
                    <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="500MB"/>
                </Policies>
            </RollingFile>
        </Appenders>
        <Loggers>
            <Logger name="com.meituan.Main" level="trace" additivity="false">
                <!--Logger的Filter-->
                <ThresholdFilter level="debug"/>
                <appender-ref ref="RollingFile"/>
            </Logger>
            <Root level="debug">
                <AppenderRef ref="Console"/>
            </Root>
        </Loggers>
    </Configuration>

    java代码如下:

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class Main {
        public static void main(String args[]) {
            Logger logger = LogManager.getLogger(Main.class);
            Person person = new Person("Li", "lei");
            logger.info("hello, {}", person);
        }
    
        private static class Person {
            private String firstName;
            private String lastName;
    
            public Person(String firstName, String lastName) {
                this.firstName = firstName;
                this.lastName = lastName;
            }
    
            public String toString() {
                return "Person[" + firstName + "," + lastName + "]";
            }
        }
    }

    使用以上的配置,当我们运行程序后,以下log将被添加到logs/app.log中。

    2017-09-13 19:41:00,889 INFO c.m.Main [main] hello, Person[Li,lei]

    logger.info运行时到底发生了什么?日志信息是如何输出到app.log中的?

    Log4j2中日志输出的详细过程如下:

    1.首先使用全局Filter对日志事件进行过滤。

    Log4j2中的日志Level分为8个级别,优先级从高到低依次为OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。

    全局Filter的Level为ALL,表示允许输出所有级别的日志。logger.info()请求输出INFO级别的日志,通过。

    2.使用Logger的Level对日志事件进行过滤。

    Logger的Level为TRACE,表示允许输出TRACE级别及以上级别的日志。logger.info()请求输出INFO级别的日志,通过。

    3.生成日志输出内容Message。

    使用占位符的方式输出日志,输出语句为logger.info("increase {} from {} to {}", arg1, arg2, arg3)的形式,最终输出时{}占位符处的内容将用arg1,arg2,arg3的字符串填充。

    log4j2用Object[]保存参数信息,在这一阶段会将Object[]转换为String[],生成含有输出模式串"increase {} from {} to {}"和参数数组String[]的Message,为后续日志格式化输出做准备。

    4.生成LogEvent。

    LogEvent中含有loggerName(日志的输出者),level(日志级别),timeMillis(日志的输出时间),message(日志输出内容),threadName(线程名称)等信息。

    在上述程序中,生成的LogEvent的属性值为loggerName=com.meituan.Main,Level=INFO,timeMillis=1505659461759,message为步骤3中创建的Message,threadNama=main。

    5.使用Logger配置的Filter对日志事件进行过滤。

    Logger配置的Filter的Level为DEBUG,表示允许输出DEBUG及以上级别的日志。logger.info()请求输出INFO级别的日志,通过。

    6.使用Logger对应的Appender配置的Filter对日志事件进行过滤。

    Appender配置的Filter配置的INFO级别日志onMatch=ACCEPT,表示允许输出INFO级别的日志。logger.info()请求输出INFO级别的日志,通过。

    7.判断是否需要触发rollover。

    此步骤不是日志输出的必须步骤,如配置的Appender为无需进行rollover的Appender,则无此步骤。

    因为使用RollingFileAppender,且配置了基于文件大小的rollover触发策略,在此阶段会判断是否需要触发rollover。判断方式为当前的文件大小是否达到了指定的size,如果达到了,触发rollover操作。关于Log4j2中的RollingFileAppender的rollover,可参见Log4j2中RollingFile的文件滚动更新机制

    8.PatternLayout对LogEvent进行格式化,生成可输出的字符串。

    上述log4j2.xml文件中配置的Pattern及各个参数的意义如下:

    <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>

    参数

    意义

    %d
    日期格式,默认形式为2012-11-02 14:34:02,781
    %p
    日志级别
    %c{1.}
    %c表示Logger名字,{1.}表示精确度。若Logger名字为org.apache.commons.Foo,则输出o.a.c.Foo。
    %t
    处理LogEvent的线程的名字
    %m
    日志内容
    %n
    行分隔符。"\n"或"\r\n"。

    在此步骤,PatternLayout将根据Pattern的模式,利用各种Converter对LogEvent的相关信息进行转换,最终拼接成可输出的日志字符串。

    如DatePatternConverter对LogEvent的日志输出时间进行格式化转换;LevelPatternConverter对LogEvent的日志级别信息进行格式化转换;LoggerPatternConverter对LogEvent的Logger的名字进行格式化转换;MessagePatternConverter对LogEvent的日志输出内容进行格式化转换等。

    经各种Converter转换后,LogEvent的信息被格式化为指定格式的字符串。

    9.使用OutputStream,将日志输出到文件。

    将日志字符串序列化为字节数组,使用字节流OutoutStream将日志输出到文件中。如果配置了immediateFlush为true,打开app.log就可观察到输出的日志了。

    3.Log4j2中的异步日志

    使用log4j2的同步日志进行日志输出,日志输出语句与程序的业务逻辑语句将在同一个线程运行,如上面的例子,打印的日志中显示的线程名称为main,与业务逻辑语句在同一个线程中(此句有误,LogEvent中的线程名称不是输出LogEvent的线程,是生成LogEvent的线程,输出LogEvent的线程和生成LogEvent可能不是一个线程!)

    而使用异步日志进行输出时,日志输出语句与业务逻辑语句并不是在同一个线程中运行,而是有专门的线程用于进行日志输出操作,处理业务逻辑的主线程不用等待即可执行后续业务逻辑。

    Log4j2中的异步日志实现方式有AsyncAppender和AsyncLogger两种。

    其中,AsyncAppender采用了ArrayBlockingQueue来保存需要异步输出的日志事件;AsyncLogger则使用了Disruptor框架来实现高吞吐。

    3.1 AsyncAppender

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="warn">
      <Appenders>
        <RollingFile name="MyFile" fileName="logs/app.log">
          <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
          </PatternLayout>
          <SizeBasedTriggeringPolicy size="500MB"/>
        </RollingFile>
        <Async name="Async">
          <AppenderRef ref="MyFile"/>
        </Async>
      </Appenders>
      <Loggers>
        <Root level="error">
          <AppenderRef ref="Async"/>
        </Root>
      </Loggers>
    </Configuration>

    上面就是一个使用AsyncAppender的典型配置,配置AsyncAppender后,日志事件写入文件的操作将在单独的线程中执行。

    AsyncAppender的常用参数

    参数名

    类型

    说明

    nameStringAsync Appender的名字。
    AppenderRefString

    异步调用的Appender的名字,可以配置多个。

    blockingboolean

    默认为true。如果为true,appender将一直等待直到queue中有空闲;如果为false,当队列满的时候,日志事件将被丢弃。(如果配置了error appender,要丢弃的日志事件将由error appender处理)

    bufferSizeinteger

    队列中可存储的日志事件的最大数量,默认为128。(源码中为128,Log4j2官网为1024,官网信息有误)

    关于AsyncAppender的其他参数,可参考Log4j2对AsyncAppender的详细介绍。

    每个Async Appender,内部维护了一个ArrayBlockingQueue,并将创建一个线程用于输出日志事件,如果配置了多个AppenderRef,将分别使用对应的Appender进行日志输出。

    3.2 AsyncLogger

    Log4j2中的AsyncLogger的内部使用了Disruptor框架。

    Disruptor简介

    Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,基于Disruptor开发的系统单线程能支撑每秒600万订单。

    目前,包括Apache Strom、Log4j2在内的很多知名项目都应用了Disruptor来获取高性能。

    Disruptor框架内部核心数据结构为RingBuffer,其为无锁环形队列。

     

    单线程每秒能够处理600万订单,Disruptor为什么这么快?

    a.lock-free-使用了CAS来实现线程安全

    ArrayBlockingQueue使用锁实现并发控制,当get或put时,当前访问线程将上锁,当多生产者、多消费者的大量并发情形下,由于锁竞争、线程切换等,会有性能损失。

    Disruptor通过CAS实现多生产者、多消费者对RingBuffer的并发访问。CAS相当于乐观锁,其性能优于Lock的性能。

    b.使用缓存行填充解决伪共享问题

    计算机体系结构中,内存的访问速度远远低于CPU的运行速度,在内存和CPU之间,加入Cache,CPU首先访问Cache中的数据,CaChe未命中,才访问内存中的数据。

    伪共享:Cache是以缓存行(cache line)为单位存储的,当多个线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能。

     

    关于伪共享的深度分析,可参考《伪共享,并发编程的性能杀手》这篇文章。

    AsyncLogger

    Log4j2异步日志如何进行日志输出,我们同样从一个例子出发来探究Log4j2的异步日志。

    log4j2.xml配置如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="debug" name="MyApp" packages="">
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            </Console>
            <RollingFile name="RollingFile" fileName="logs/app.log"
                         filePattern="logs/app-%d{yyyy-MM-dd HH}.log">
                <PatternLayout>
                    <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="500MB"/>
                </Policies>
            </RollingFile>
            <RollingFile name="RollingFile2" fileName="logs/app2.log"
                         filePattern="logs/app2-%d{yyyy-MM-dd HH}.log">
                <PatternLayout>
                    <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="500MB"/>
                </Policies>
            </RollingFile>
        </Appenders>
        <Loggers>
            <AsyncLogger name="com.meituan.Main" level="trace" additivity="false">
                <appender-ref ref="RollingFile"/>
            </AsyncLogger>
            <AsyncLogger name="RollingFile2" level="trace" additivity="false">
                <appender-ref ref="RollingFile2"/>
            </AsyncLogger>
            <Root level="debug">
                <AppenderRef ref="Console"/>
                <AppenderRef ref="RollingFile"/>
            </Root>
        </Loggers>
    </Configuration>

    java代码如下:

    public class Main {
        public static void main(String args[]) {
            Logger logger = LogManager.getLogger(Main.class);
            Logger logger2 = LogManager.getLogger("RollingFile2");
    
            Person person = new Person("Li", "lei");
            logger.info("hello, {}", person);
            logger2.info("good bye, {}", person);
    }

    上述log4j2.xml中配置了两个AsyncLogger,名字分别为com.meituan.Main和RollingFile2。

    并且,在main方法中分别使用两个logger来输出两条日志。

     

    在加载log4j2.xml的启动阶段,如果检测到配置了AsyncRoot或AsyncLogger,将启动一个disruptor实例。

    上述程序中,main线程作为生产者,EventProcessor线程作为消费者。

    生产者生产消息

    当运行到类似于logger.info、logger.debug的输出语句时,将生成的LogEvent放入RingBuffer中。

    消费者消费消息

    如果RingBuffer中有LogEvent需要处理,EventProcessor线程从RingBuffer中取出LogEvent,调用Logger相关联的Appender输出LogEvent(具体输出过程与同步过程相同,同样需要过滤器过滤、PatternLayout格式化等步骤)。

    如果RingBuffer中没有LogEvent需要处理,EventProcessor线程将处于等待阻塞状态(默认策略)。

    需要注意的是,虽然在log4j2.xml中配置了多个AsyncLogger,但是并不是每个AsyncLogger对应着一个处理线程,而是仅仅有一个EventProcessor线程进行日志的异步处理。

    4.总结

     

    日志输出方式

    sync同步打印日志,日志输出与业务逻辑在同一线程内,当日志输出完毕,才能进行后续业务逻辑操作
    Async Appender异步打印日志,内部采用ArrayBlockingQueue,对每个AsyncAppender创建一个线程用于处理日志输出。
    Async Logger异步打印日志,采用了高性能并发框架Disruptor,创建一个线程用于处理日志输出。
    展开全文
  • https://www.cnblogs.com/yeyang/p/7944906.html 同步日志异步日志 https://blog.csdn.net/RyanDon/article/details/82589989 https://www.jianshu.com/p/5dcf4ece0de3 log4j2 依赖 spring-boot-starter-log4j2 ...

    参考

    https://www.cnblogs.com/yeyang/p/7944906.html 同步日志和异步日志
    https://blog.csdn.net/RyanDon/article/details/82589989
    https://www.jianshu.com/p/5dcf4ece0de3

    log4j2 依赖 spring-boot-starter-log4j2

    注意,spring-boot-starter自带日志依赖,需要用 exclusion 排除掉

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-log4j2</artifactId>
            </dependency>
            
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-logging</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    

    log4j2 的 springboot默认配置

    如果没有配置log4j2的话,log4j2会有默认配置,默认将info及以上级别的日志同步输出到控制台,如下:
    在这里插入图片描述

        public final static Logger logger = LoggerFactory.getLogger(UserController.class);
    
        @RequestMapping("/test")
        public String addUser() {
            //参数 string
            logger.trace("trace level");
            logger.debug("debug level");
            logger.info("info level");
            logger.warn("warn level");
            logger.error("error level");
    
            //格式化生成message , 占位符 {}
            logger.info("1 + {} + 3 = {}" ,2,"6");
    
            //输出异常信息
            logger.info("异常信息:",new Exception("hhhhhhhhhhhhhhh"));
            return  "";
        }
    
    控制台输出结果
    2019-08-05 17:42:45.666  INFO 3564 --- [nio-8096-exec-1] c.e.l.c.UserController                   : info level
    2019-08-05 17:42:45.666  WARN 3564 --- [nio-8096-exec-1] c.e.l.c.UserController                   : warn level
    2019-08-05 17:42:45.666 ERROR 3564 --- [nio-8096-exec-1] c.e.l.c.UserController                   : error level
    2019-08-05 17:42:45.667  INFO 3564 --- [nio-8096-exec-1] c.e.l.c.UserController                   : 1 + 2 + 3 = 6
    2019-08-05 17:42:45.667  INFO 3564 --- [nio-8096-exec-1] c.e.l.c.UserController                   : 异常信息:
    
    java.lang.Exception: hhhhhhhhhhhhhhh
    	at com.example.log4j2_demo.controller.UserController.addUser(UserController.java:27) [classes/:?]
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
    	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
    	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) [spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) [spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) [tomcat-embed-core-9.0.21.jar:9.0.21]
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.21.jar:9.0.21]
    
    

    log4j2 的 xml配置,大致如下:

    • Configuration
      • properties
      • Appenders
        • Console
          • PatternLayout
        • File
          • PatternLayout
        • RollingRandomAccessFile
        • Async (Async Appender异步,内部采用ArrayBlockingQueue)
          • AppenderRef 指定具体哪个Appender采用Async Appender异步
      • Loggers
        • Root
          • AppenderRef
        • Logger
          • AppenderRef
        • AsyncLogger (Async Logger异步,采用了高性能并发框架Disruptor,高性能)
          • appender-ref 指定具体哪个Appender采用Async Logger异步

    同步log4j2 xml配置如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
        <properties>
            <property name="LOG_HOME">../logs</property>
            <property name="FILE_NAME">mylog</property>
            <property name="log.sql.level">info</property>
        </properties>
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">  
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n" />  
            </Console>
            <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>
                <Policies>
                    <TimeBasedTriggeringPolicy interval="1"/>
                    <SizeBasedTriggeringPolicy size="10 MB"/>
                </Policies>
                <DefaultRolloverStrategy max="20"/>
            </RollingRandomAccessFile>
        </Appenders>
        <Loggers>
            <Root level="info">  
                <AppenderRef ref="Console" />  
                <AppenderRef ref="RollingRandomAccessFile" />  
            </Root>
            <Logger name="com.mengdee.dao" level="${log.sql.level}" additivity="false">
                <AppenderRef ref="Console" />
            </Logger>
        </Loggers>
    </Configuration>
    

    log4j2配置介绍

    • Configuration:为根节点,有status和monitorInterval等多个属性

      • status的值有 “trace”, “debug”, “info”, “warn”, “error” and “fatal”,用于控制log4j2日志框架 本身 的日志级别,如果将stratus设置为较低的级别就会看到很多关于log4j2本身的日志,如加载log4j2配置文件的路径等信息
        注意:这个属性是针对框架本身信息,不针对我们用logger输出的信息.

      • monitorInterval,含义是每隔多少秒重新读取配置文件,可以不重启应用的情况下修改配置

    • properties: 属性
      使用来定义常量,以便在其他配置的时候引用,该配置是可选的,例如定义日志的存放位置 …/logs

    • Appenders:输出源,用于定义日志输出的地方
      log4j2支持的输出源有很多,有控制台Console、文件File、RollingRandomAccessFile、MongoDB、Flume 等

      • Console:控制台输出源是将日志打印到控制台上,开发的时候一般都会配置,以便调试

      • File:文件输出源,用于将日志写入到指定的文件,需要配置输入到哪个位置(例如:D:/logs/mylog.log)

      • RollingRandomAccessFile: 该输出源也是写入到文件,不同的是比File更加强大,可以指定当文件达到一定大小(如20MB)时,另起一个文件继续写入日志,另起一个文件就涉及到新文件的名字命名规则,因此需要配置文件命名规则
        这种方式更加实用,因为你不可能一直往一个文件中写,如果一直写,文件过大,打开就会卡死,也不便于查找日志。

        • fileName 指定当前日志文件的位置和文件名称

        • filePattern 指定当发生Rolling时,文件的转移和重命名规则

        • SizeBasedTriggeringPolicy 指定当文件体积大于size指定的值时,触发Rolling

        • DefaultRolloverStrategy 指定最多保存的文件个数

        • TimeBasedTriggeringPolicy 这个配置需要和filePattern结合使用,注意filePattern中配置的文件重命名规则是${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i,最小的时间粒度是mm,即分钟

        • TimeBasedTriggeringPolicy指定的size是1,结合起来就是每1分钟生成一个新文件。如果改成%d{yyyy-MM-dd HH},最小粒度为小时,则每一个小时生成一个文件

        • PatternLayout:控制台或文件输出源(Console、File、RollingRandomAccessFile)都必须包含一个PatternLayout节点,用于指定输出文件的格式(如 日志输出的时间 文件 方法 行数 等格式),例如 pattern=”%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n”

            %d{HH:mm:ss.SSS} 表示输出到毫秒的时间
            %t 输出当前线程名称
            %-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
            %logger 输出logger名称,因为Root Logger没有名称,所以没有输出
            %msg 日志文本
            %n 换行
          
            其他常用的占位符有:
            %F 输出所在的类文件名,如Log4j2Test.java
            %L 输出行号
            %M 输出所在方法名
            %l 输出语句所在的行数, 包括类名、方法名、文件名、行数
          
      • NoSql:MongoDb, 输出到MongDb数据库中

      • Flume:输出到Apache Flume(Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力。)

      • Async:异步,需要通过AppenderRef来指定要对哪种输出源进行异步(一般用于配置RollingRandomAccessFile)

    • Loggers:日志分根器
      日志器分根器 : Root和自定义日志器,当根据日志名字获取不到指定的日志器时就使用Root作为默认的日志器,自定义时需要指定每个Logger的名称name(对于命名可以以包名作为日志的名字,不同的包配置不同的级别等),日志级别level,相加性additivity(是否继承下面配置的日志器), 对于一般的日志器(如Console、File、RollingRandomAccessFile)一般需要配置一个或多个输出源AppenderRef;

      每个logger可以指定一个level(TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF),不指定 时level默认为ERROR

      additivity指定是否同时输出log到父类的appender,缺省为true。

    Async Appender异步 log4j2 xml配置 举例如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="warn">
      <Appenders>
        <RollingFile name="MyFile" fileName="logs/app.log">
          <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
          </PatternLayout>
          <SizeBasedTriggeringPolicy size="500MB"/>
        </RollingFile>
        <Async name="Async">
          <AppenderRef ref="MyFile"/>
        </Async>
      </Appenders>
      <Loggers>
        <Root level="error">
          <AppenderRef ref="Async"/>
        </Root>
      </Loggers>
    </Configuration>
    

    上面就是一个使用AsyncAppender的典型配置,配置AsyncAppender后,日志事件写入文件的操作将在单独的线程中执行
    AsyncAppender的常用参数

    参数名类型说明
    nameStringAsync Appender的名字。
    AppenderRefString异步调用的Appender的名字,可以配置多个。
    blockingboolean默认为true。如果为true,appender将一直等待直到queue中有空闲;如果为false,当队列满的时候,日志事件将被丢弃。(如果配置了error appender,要丢弃的日志事件将由error appender处理)
    bufferSizeinteger队列中可存储的日志事件的最大数量,默认为128。(源码中为128,Log4j2官网为1024,官网信息有误)

    关于AsyncAppender的其他参数,可参考Log4j2对AsyncAppender的详细介绍

    每个Async Appender,内部维护了一个ArrayBlockingQueue,并将创建一个线程用于输出日志事件,如果配置了多个AppenderRef,将分别使用对应的Appender进行日志输出。

    AsyncLogger 异步 log4j2 xml配置 举例如下:

    Log4j2中的AsyncLogger的内部使用了Disruptor框架。

    
    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="debug" name="MyApp" packages="">
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            </Console>
            <RollingFile name="RollingFile" fileName="logs/app.log"
                         filePattern="logs/app-%d{yyyy-MM-dd HH}.log">
                <PatternLayout>
                    <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="500MB"/>
                </Policies>
            </RollingFile>
            <RollingFile name="RollingFile2" fileName="logs/app2.log"
                         filePattern="logs/app2-%d{yyyy-MM-dd HH}.log">
                <PatternLayout>
                    <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="500MB"/>
                </Policies>
            </RollingFile>
        </Appenders>
        <Loggers>
            <AsyncLogger name="com.meituan.Main" level="trace" additivity="false">
                <appender-ref ref="RollingFile"/>
            </AsyncLogger>
            <AsyncLogger name="RollingFile2" level="trace" additivity="false">
                <appender-ref ref="RollingFile2"/>
            </AsyncLogger>
            <Root level="debug">
                <AppenderRef ref="Console"/>
                <AppenderRef ref="RollingFile"/>
            </Root>
        </Loggers>
    </Configuration>
    

    java代码使用上面 配置的log4j2,输出日志信息

    
    public class Main {
        public static void main(String args[]) {
            Logger logger = LogManager.getLogger(Main.class);
            Logger logger2 = LogManager.getLogger("RollingFile2");
     
            Person person = new Person("Li", "lei");
            logger.info("hello, {}", person);
            logger2.info("good bye, {}", person);
    }
    

    上述log4j2.xml中配置了两个AsyncLogger,名字分别为com.meituan.Main和RollingFile2。
    并且,在main方法中分别使用两个logger来输出两条日志。

    在加载log4j2.xml的启动阶段,如果检测到配置了AsyncRoot或AsyncLogger,将启动一个disruptor实例。

    配置对应的输出方式

    配置日志输出方式
    sync同步打印日志,日志输出与业务逻辑在同一线程内,当日志输出完毕,才能进行后续业务逻辑操作
    Async异步打印日志,内部采用ArrayBlockingQueue,对每个AsyncAppender创建一个线程用于处理日志输出。
    AsyncLogger异步打印日志,采用了高性能并发框架Disruptor,创建一个线程用于处理日志输出。

    各种配置的性能

    • 吞吐量测试
      在这里插入图片描述
    • 平均耗时
      在这里插入图片描述
    展开全文
  • Log4j 2中记录日志的方式有同步日志异步日志两种方式, 其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式。 1、Log4j2中的同步日志 所谓同步日志,即当输出日志时,必须等待日志输出语句...

    https://www.cnblogs.com/yeyang/p/7944906.html
    https://www.cnblogs.com/yangfeiORfeiyang/p/9775863.html
    https://blog.csdn.net/henrydlwang/article/details/78939031
    https://www.jianshu.com/p/9f0c67facbe2

    Log4j 2中记录日志的方式有同步日志和异步日志两种方式,
    其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式。

    1、Log4j2中的同步日志

    所谓同步日志,即当输出日志时,必须等待日志输出语句执行完毕后,才能执行后面的业务逻辑语句。

    即:只有一个线程 同时处理 业务逻辑 和 日志逻辑

    2、Log4j2中的异步日志

    使用异步日志进行输出时,日志输出 与 业务逻辑 并不是在同一个线程中运行,而是有专门的线程用于进行日志输出操作,处理业务逻辑的主线程不用等待即可执行后续业务逻辑。

    Log4j2中的异步日志实现方式有AsyncAppender和AsyncLogger两种。

    • AsyncAppender采用了ArrayBlockingQueue来保存需要异步输出的日志事件;
    • AsyncLogger则使用了Disruptor框架来实现高吞吐。

    (1)、每个Async Appender,内部维护了一个ArrayBlockingQueue,将创建一个线程用于输出日志事件 【线程一一对应】

    (2)、Disruptor简介 

    Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,基于Disruptor开发的系统单线程能支撑每秒600万订单。
    目前,包括Apache Strom、Log4j2在内的很多知名项目都应用了Disruptor来获取高性能。
    Disruptor框架内部核心数据结构为RingBuffer,其为无锁环形队列。

    并不是每个AsyncLogger对应着一个处理线程,而是仅仅有一个EventProcessor线程进行日志的异步处理。 【只多了一个线程】

    3、实际应用中的3中配置方式

    (1)全异步   jvm启动的时候增加一个参数 (AsyncAppender和AsyncLogger 同时使用)

    (2)混合异步   Logger  既有同步也有异步

    (3)全同步  ---默认就是吧(网上没搜到答案,估计应该是这样)

    4、同步异步使用注意事项

    • 1、混合异步和同步Logger;root logger 为同步,其它为异步;
    • 2、AsyncLogger 的additivity属性设置为false;
    • 3、不要同时使用AsyncAppender和AsyncLogger,也就是在配置中不要在配置Appender的时候,使用Async标识的同时,又配置AsyncLogger,这不会报错,但是对于性能提升没有任何好处。
    • 4、不管是同步异步,都设置 immediateFlush为false,这会对性能提升有很大帮助。
    • 5、如果不是确实需要,不要打印location信息,比如HTML的location,或者pattern模式里的%C or $class, %F or %file, %l or %location, %L or %line, %M or %method, 等,因为Log4j需要在打印日志的时候做一次栈的快照才能获取这些信息,这对于性能来说是个极大的损耗。

    观察官网给出的性能测试数据:

    综合使用注意事项,可得出结论(推荐使用方式):【变 Logger ,Appender 保持不动】

    • 1、混合异步和同步Logger;root logger 为同步,其它为异步;
    • 2、AsyncLogger 的additivity属性设置为false;

     

    展开全文
  • 主要介绍了 log4j 详解异步日志的配置和测试的相关资料,需要的朋友可以参考下
  • LogBack异步记录日志

    千次阅读 2019-08-22 16:58:17
    前言 最近在对项目中的一些接口进行压测,但是压测的结果并不是很理想,接口的响应时间下不来,而吞吐量也迟迟上不去,...LogBack日志同步记录更改为异步记录并不需要更改原配置,只需要在原配置的基础上再增加一...
  • Log4j 2中记录日志的方式有同步日志异步日志两种方式,其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式。 同步日志 所谓同步日志,即当输出日志时,必须等待日志输出语句执行完毕后,才能执行...
  • 同步异步区别

    2018-03-23 12:21:58
    同步:方法调用者只能一件一件的干事,必须要等到结果之后,才能...异步:在通常情况下,比同步执行效率高。当程序在对象式调用一个需要执行很长时间的方法,并且不希望等待程序执行返回结果,这时就使用异步操作。...
  • 同步日志 混合同步和异步日志 异步日志(性能最好,推荐使用) []( )同步日志 所谓同步日志,即当输出日志时,必须等待日志输出语句执行完毕后,才能执行后面的业务逻辑语句。 下面给出小编在开发中的配置 &...
  • 混合同步异步日志 Log4j-2.9及更高版本在类路径上需要disruptor-3.3.4.jar或更高版本。在Log4j-2.9之前,需要disruptor-3.0.0.jar或更高版本。无需将系统属性“Log4jContextSelector”设置为任何值。 可以在配置...
  • logback日志异步打印

    千次阅读 2019-01-31 15:50:00
    最近碰到一个问题:客户的服务器程序偶尔出现请求响应过慢的情况,通过查看日志发现RSA验证签名的代码执行超过20秒,而正常情况下只需要16毫秒。 RSA证书是服务器启动就加载好的,不存在读文件慢的问题。看了一下那...
  • 同步复制与异步复制

    万次阅读 2021-06-21 10:36:30
    主从复制:其中一种设计,包括一个同步的从节点,和一个异步的从节点。 从节点2在接收复制日志之前有一段很长的延迟。通常情况下,复制速度会非常快,例如多数数据库系统可以在一秒之内完成所有从节点的更新。但是,...
  • 文件同步与异步读写

    2012-05-25 10:58:27
    里面包含两个文件,一个是从网上找到的vc6.0下读文件程序,另外一个是自己编写的VS2005下写文件程序,都包含了同步异步方式。在VS2005下运行通过。
  • logback 异步日志配置

    千次阅读 2017-07-03 16:03:39
    目前所有的日志记录方式采用的都是同步的方式,即直接将日志写入文件。 在多应用的时候,这种效果会导致一定的...异步日志记录是在原来logback上的扩展,并不是替代方式,所以只需要在原来的配置文件上添加一下配置
  • logback异步记录日志

    千次阅读 2018-07-05 11:10:04
    异步记录日志注意:该功能需要高版本才能支持,如1.0.11。AsyncAppender,异步记录日志。工作原理:当Logging Event进入AsyncAppender后,AsyncAppender会调用appender方法,append方法中在将event填入Buffer(这里...
  • 一、前言最近刚刚结束转岗以来的第一次双11压测,收获颇多,难以言表, 本文就先...二、日志打印模型同步日志模型如上图,多个业务线程打印日志时候要等把内容写入磁盘后才会返回,所以打日志的rt就是写入磁盘的耗时...
  • muduo异步日志总结

    2020-12-20 23:05:04
    与同步日志又有什么区别同步日志与异步日志 同步日志:网络IO线程或业务线程直接向磁盘文件中写日志信息,只有等一条日志消息写完之后才能执行后续的程序。同步日志容易阻塞在磁盘IO上,效率较低且影响服务器性能...
  • 前言关于日志,在大家的印象中都是比较简单的,只须引入了相关依赖包,剩下的事情就是在项目中“尽情”的打印我们需要的信息了。但是往往越简单的东西越容易让我们忽视,从而导致一些不该有的bug发生,作为一名严谨...
  • 所以对于react来说,只要发起一个dispatch告诉redux去处理异步,把获取到的数据存到store里面,在界面需要的时候,直接能取出来用就可以了,界面再也不用担心异步回调事件。所以一般用了redux就会配合使用 redux-...
  • 8、logback-异步日志

    2022-01-16 09:27:05
    第一步:创建maven项目,添加依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=... <modelVersion>4.0
  • 本篇文章给大家带来的内容是关于logback日志异步打印的方法介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。最近碰到一个问题:客户的服务器程序偶尔出现请求响应过慢的情况,通过...
  • C++的异步日志, 其特点是效率高(实测每秒支持125+万日志写入)、易拓展,尤其适用于频繁写日志的场景
  • logback 日志异步配置

    2020-09-09 11:01:59
    对于日志输出我们使用的是 logback,日志写入的方式采用的是比较常用的同步写入文件(即 RollingFileAppender),logback-spring.xml 配置如下: <?xml version="1.0" encoding="UTF-8"?> <configuration&...
  • 一、前言最近刚刚结束转岗以来的第一次双11压测,收获颇多,难言言表, 本文就先谈谈异步...二、日志打印模型同步日志模型image.png如上图,多个业务线程打印日志时候要等把内容写入磁盘后才会返回,所以打日志的rt...
  • 线程同步与异步

    千次阅读 2018-08-29 11:50:32
    线程同步与异步 线程 同步 (synchronized) 异步 (asynchronized) 特点 A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求不到,怎么办,A线程只能等待下去 A线程要请求...
  • 接口日志异步入库

    2019-11-11 16:33:26
    在高并发场景下,接口日志同步入库会增加数据库压力,降低接口效率,对此,可以使用异步入库提高接口效率。 思路 使用阻塞队列保存日志对象,定时任务定时批量入库。 具体实现 创建日志Bean对象,具体字段...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 134,059
精华内容 53,623
关键字:

同步日志与异步日志区别