On our side, we did not find the logging provided by -Djdk.internal.httpclient.debug readable enough. The solution we came up with is to wrap the HttpClient with a decorator that will be able to intercept the calls and provide logging. Here how it somehow looks (should be done not only for send but sendAsync methods) :
public class HttpClientLoggingDecorator extends HttpClient {
  private static final Logger logger = Logger.getLogger(HttpClientLoggingDecorator.class.getName());
  private final HttpClient client;
  ...
  @Override
  public <T> HttpResponse<T> send(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler)
    throws IOException,
      InterruptedException
  {
    subscribeLoggerToRequest(req);
    HttpResponse<T> response = client.send(req, responseBodyHandler);
    logResponse(response);
    return response;
  }
  private void subscribeLoggerToRequest(HttpRequest req) {
    // define a consumer for how you want to log
    // Consumer<String> bodyConsumer = ...;
    if (req.bodyPublisher().isPresent()) {
      req.bodyPublisher().get().subscribe(new HttpBodySubscriber(bodyConsumer)));
    } else {
      bodyConsumer.accept(NO_REQUEST_BODY);
    }
  }
  private <T> void logResponse(HttpResponse<T> response) {
    // String responseLog = ...;
    logger.info(responseLog);
  }
}
And here is the HttpBodySubscriber:
public class HttpBodySubscriber implements Flow.Subscriber<ByteBuffer> {
  private static final long UNBOUNDED = Long.MAX_VALUE;
  private final Consumer<String> logger;
  public HttpBodySubscriber(Consumer<String> logger) {
    this.logger = logger;
  }
  @Override
  public void onSubscribe(Flow.Subscription subscription) {
    subscription.request(UNBOUNDED);
  }
  @Override
  public void onNext(ByteBuffer item) {
    logger.accept(new String(item.array(), StandardCharsets.UTF_8));
  }
  @Override
  public void onError(Throwable throwable) {
  }
  @Override
  public void onComplete() {
  }
}