@Override
  public void start() {
    final Map<String, Appender> map = config.getAppenders();
    final List<AppenderControl> appenders = new ArrayList<>();
    for (final AppenderRef appenderRef : appenderRefs) {
      if (map.containsKey(appenderRef.getRef())) {
        appenders.add(
            new AppenderControl(
                map.get(appenderRef.getRef()), appenderRef.getLevel(), appenderRef.getFilter()));
      } else {
        LOGGER.error("No appender named {} was configured", appenderRef);
      }
    }
    if (errorRef != null) {
      if (map.containsKey(errorRef)) {
        errorAppender = new AppenderControl(map.get(errorRef), null, null);
      } else {
        LOGGER.error(
            "Unable to set up error Appender. No appender named {} was configured", errorRef);
      }
    }
    if (appenders.size() > 0) {
      thread = new AsyncThread(appenders, queue);
      thread.setName("AsyncAppender-" + getName());
    } else if (errorRef == null) {
      throw new ConfigurationException("No appenders are available for AsyncAppender " + getName());
    }

    thread.start();
    super.start();
  }
 @Override
 public void stop() {
   super.stop();
   LOGGER.trace("AsyncAppender stopping. Queue still has {} events.", queue.size());
   thread.shutdown();
   try {
     thread.join();
   } catch (final InterruptedException ex) {
     LOGGER.warn("Interrupted while stopping AsyncAppender {}", getName());
   }
   LOGGER.trace("AsyncAppender stopped. Queue has {} events.", queue.size());
 }
 /**
  * Actual writing occurs here.
  *
  * @param logEvent The LogEvent.
  */
 @Override
 public void append(LogEvent logEvent) {
   if (!isStarted()) {
     throw new IllegalStateException("AsyncAppender " + getName() + " is not active");
   }
   if (!(logEvent instanceof Log4jLogEvent)) {
     if (!(logEvent instanceof RingBufferLogEvent)) {
       return; // only know how to Serialize Log4jLogEvents and RingBufferLogEvents
     }
     logEvent = ((RingBufferLogEvent) logEvent).createMemento();
   }
   logEvent.getMessage().getFormattedMessage(); // LOG4J2-763: ask message to freeze parameters
   final Log4jLogEvent coreEvent = (Log4jLogEvent) logEvent;
   boolean appendSuccessful = false;
   if (blocking) {
     if (isAppenderThread.get() == Boolean.TRUE && queue.remainingCapacity() == 0) {
       // LOG4J2-485: avoid deadlock that would result from trying
       // to add to a full queue from appender thread
       coreEvent.setEndOfBatch(false); // queue is definitely not empty!
       appendSuccessful = thread.callAppenders(coreEvent);
     } else {
       final Serializable serialized = Log4jLogEvent.serialize(coreEvent, includeLocation);
       try {
         // wait for free slots in the queue
         queue.put(serialized);
         appendSuccessful = true;
       } catch (final InterruptedException e) {
         // LOG4J2-1049: Some applications use Thread.interrupt() to send
         // messages between application threads. This does not necessarily
         // mean that the queue is full. To prevent dropping a log message,
         // quickly try to offer the event to the queue again.
         // (Yes, this means there is a possibility the same event is logged twice.)
         //
         // Finally, catching the InterruptedException means the
         // interrupted flag has been cleared on the current thread.
         // This may interfere with the application's expectation of
         // being interrupted, so when we are done, we set the interrupted
         // flag again.
         appendSuccessful = queue.offer(serialized);
         if (!appendSuccessful) {
           LOGGER.warn(
               "Interrupted while waiting for a free slot in the AsyncAppender LogEvent-queue {}",
               getName());
         }
         // set the interrupted flag again.
         Thread.currentThread().interrupt();
       }
     }
   } else {
     appendSuccessful = queue.offer(Log4jLogEvent.serialize(coreEvent, includeLocation));
     if (!appendSuccessful) {
       error("Appender " + getName() + " is unable to write primary appenders. queue is full");
     }
   }
   if (!appendSuccessful && errorAppender != null) {
     errorAppender.callAppender(coreEvent);
   }
 }
  @Override
  public boolean stop(final long timeout, final TimeUnit timeUnit) {
    setStopping();
    super.stop(timeout, timeUnit, false);
    LOGGER.trace("AsyncAppender stopping. Queue still has {} events.", queue.size());
    thread.shutdown();
    try {
      thread.join(shutdownTimeout);
    } catch (final InterruptedException ex) {
      LOGGER.warn("Interrupted while stopping AsyncAppender {}", getName());
    }
    LOGGER.trace("AsyncAppender stopped. Queue has {} events.", queue.size());

    if (DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy) > 0) {
      LOGGER.trace(
          "AsyncAppender: {} discarded {} events.",
          asyncQueueFullPolicy,
          DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy));
    }
    setStopped();
    return true;
  }
 /**
  * Actual writing occurs here.
  *
  * @param logEvent The LogEvent.
  */
 @Override
 public void append(final LogEvent logEvent) {
   if (!isStarted()) {
     throw new IllegalStateException("AsyncAppender " + getName() + " is not active");
   }
   if (!canFormatMessageInBackground(logEvent.getMessage())) {
     logEvent.getMessage().getFormattedMessage(); // LOG4J2-763: ask message to freeze parameters
   }
   final Log4jLogEvent memento = Log4jLogEvent.createMemento(logEvent, includeLocation);
   if (!transfer(memento)) {
     if (blocking) {
       // delegate to the event router (which may discard, enqueue and block, or log in current
       // thread)
       final EventRoute route = asyncQueueFullPolicy.getRoute(thread.getId(), memento.getLevel());
       route.logMessage(this, memento);
     } else {
       error("Appender " + getName() + " is unable to write primary appenders. queue is full");
       logToErrorAppenderIfNecessary(false, memento);
     }
   }
 }
 /**
  * FOR INTERNAL USE ONLY.
  *
  * @param logEvent the event to log
  */
 public void logMessageInCurrentThread(final LogEvent logEvent) {
   logEvent.setEndOfBatch(queue.isEmpty());
   final boolean appendSuccessful = thread.callAppenders(logEvent);
   logToErrorAppenderIfNecessary(appendSuccessful, logEvent);
 }