private void handleEvent(LoggingEvent event) throws InterruptedException {
    // Serialize the event before adding to the queue to leverage the caller thread
    // and ensure that the transferThread can keep up.
    if (!logQueue.offer(serde.toBytes(subLog(event)), queueTimeoutS, TimeUnit.SECONDS)) {
      // Do NOT retry adding to the queue. Dropping the event allows us to alleviate the unlikely
      // possibility of a deadlock, which can arise due to a circular dependency between the SystemProducer
      // which is used for StreamAppender and the log, which uses StreamAppender. Any locks held in the callstack
      // of those two code paths can cause a deadlock. Dropping the event allows us to proceed.

      // Scenario:
      // T1: holds L1 and is waiting for L2
      // T2: holds L2 and is waiting to produce to BQ1 which is drained by T3 (SystemProducer) which is waiting for L1

      // This has happened due to locks in Kafka and log4j (see SAMZA-1537), which are both out of our control,
      // so dropping events in the StreamAppender is our best recourse.

      // Drain the queue instead of dropping one message just to reduce the frequency of warn logs above.
      int messagesDropped = logQueue.drainTo(new ArrayList<>()) + 1; // +1 because of the current log event
      log.warn(String.format("Exceeded timeout %ss while trying to log to %s. Dropping %d log messages.",
          queueTimeoutS,
          systemStream.toString(),
          messagesDropped));

      // Emit a metric which can be monitored to ensure it doesn't happen often.
      metrics.logMessagesDropped.inc(messagesDropped);
    }
    metrics.bufferFillPct.set(Math.round(100f * logQueue.size() / DEFAULT_QUEUE_SIZE));
  }
Additional configurations needed before logging to stream. Called once in the container before the first log event is sent.
samza-log4j/src/main/java/org/apache/samza/logging/log4j/StreamAppender.java