@Override
  public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    long startTimeInMs = System.currentTimeMillis();
    boolean shouldReset = msg instanceof LastHttpContent;
    boolean isHttpContent = msg instanceof HttpContent;
    if (request != null) {
      if (msg instanceof HttpResponse) {
        HttpResponse response = (HttpResponse) msg;
        logHeaders("Response", response, publicAccessLogger.getResponseHeaders());
        logMessage.append(", ");
        logMessage.append("status=").append(response.status().code());
        logMessage.append(", ");
        structuredLogMessage.put("status", String.valueOf(response.status().code()));
        if (HttpUtil.isTransferEncodingChunked(response)) {
          responseFirstChunkStartTimeInMs = System.currentTimeMillis();
        } else {
          shouldReset = true;
        }
        //If it's 100-continue response, do not reset
        if (response.status().code() == 100) {
          shouldReset = false;
        }
      } else if (!(msg instanceof HttpContent)) {
        logger.error(
            "Sending response that is not of type HttpResponse or HttpContent. Sending response to {}. Request is of type {}. No action being taken other than logging this unexpected state.",
            ctx.channel().remoteAddress(), msg.getClass());
      }
      if (isHttpContent) {
        HttpContent httpContent = (HttpContent) msg;
        responseBytesSent += httpContent.content().readableBytes();
      }
      if (shouldReset) {
        logDurations();

        if (publicAccessLogger.structuredLoggingEnabled()) {
          // Write out the old log message as a full string, as well as add each field individually.
          structuredLogMessage.put("message", logMessage.toString());
          publicAccessLogger.logInfo(structuredLogMessage);
        } else {
          publicAccessLogger.logInfo(logMessage.toString());
        }
        reset();
      }
    }
    nettyMetrics.publicAccessLogResponseProcessingTimeInMs.update(System.currentTimeMillis() - startTimeInMs);
    super.write(ctx, msg, promise);
  }
Captures headers and other required info from request and responses, to make public access log entries
{@link PublicAccessLogger} assists in logging the required information
ambry-rest/src/main/java/com/github/ambry/rest/PublicAccessLogHandler.java