code: private String bytesToString(byte[] bytes, boolean truncate) {
          CharsetDecoder decoder = Charset.defaultCharset()
                  .newDecoder()
                  .onMalformedInput(CodingErrorAction.REPLACE)
                  .onUnmappableCharacter(CodingErrorAction.REPLACE);
          ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
          CharBuffer charBuffer;
          try {
              charBuffer = decoder.decode(byteBuffer);
          } catch (CharacterCodingException e) {
              // Shouldn't happen due to choosing REPLACE above, but Java makes us catch it anyway.
              throw new RuntimeException(e);
          }
          String s = charBuffer.toString();
          if (truncate && s.length() > TRUNCATED_STRING_MAX_LEN) {
              return new StringBuilder().append(s, 0, TRUNCATED_STRING_MAX_LEN).append("[...]").toString();
          } else {
              return s;
          }
      }
docs: Message key and payload may be arbitrary binary strings, so we should make sure we don't throw
  when logging them by using a CharsetDecoder which replaces bad data. (While in practice `new String(bytes)`
  does the same thing, the documentation for that method leaves that behavior unspecified.)
  Additionally, in contexts where Message.toString() will be logged at a high level (including exception
  messages), we truncate long keys and payloads, which may be very long binary data.