Repository: open-telemetry/opentelemetry-java
File: exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Otel2PrometheusConverter.java (Java)

Code before:
          "Conflicting metrics: Multiple metrics with name "
              + name
              + " but different units found. Dropping the one with unit "
              + b.getUnit()
              + ".");
      return null;
    }
    return new MetricMetadata(name, help, unit);
  }

  private static String typeString(MetricSnapshot snapshot) {
    // Simple helper for a log message.
    return snapshot.getClass().getSimpleName().replace("Snapshot", "").toLowerCase(Locale.ENGLISH);
  }

  private static String toLabelValue(AttributeType type, Object attributeValue) {
    if (type.isPrimitive()) {
      return attributeValue.toString();
    } else {
      return maybeToJson(attributeValue);
    }
  }

  private static String maybeToJson(Object attributeValue) {
    try {
      return OBJECT_MAPPER.writeValueAsString(attributeValue);
    } catch (JsonProcessingException e) {
      LOGGER.log(
          Level.WARNING,
          "Label value couldn't be serialized, toString() is being used as fallback value...",
          e);
      return attributeValue.toString();
    }
  }
}


Review comment (suggestion):
Since we only need to serialize non-primitive types in `AttributeType`, maybe this could be done "by hand", with a simple `StringBuilder` and a loop? This PR seems to be the only reason to have Jackson in the classpath, so maybe it's worth considering at least

Code after:
              + " but different units found. Dropping the one with unit "
              + b.getUnit()
              + ".");
      return null;
    }
    return new MetricMetadata(name, help, unit);
  }

  private static String typeString(MetricSnapshot snapshot) {
    // Simple helper for a log message.
    return snapshot.getClass().getSimpleName().replace("Snapshot", "").toLowerCase(Locale.ENGLISH);
  }

  private static String toLabelValue(AttributeType type, Object attributeValue) {
    switch (type) {
      case STRING:
      case BOOLEAN:
      case LONG:
      case DOUBLE:
        return attributeValue.toString();
      case BOOLEAN_ARRAY:
      case LONG_ARRAY:
      case DOUBLE_ARRAY:
      case STRING_ARRAY:
        if (attributeValue instanceof List) {
          return toJsonStr((List<?>) attributeValue);
        } else {
          throw new IllegalStateException(
              String.format(
                  "Unexpected label value of %s for %s",
                  attributeValue.getClass().getName(), type.name()));
        }
    }
    throw new IllegalStateException("Unrecognized AttributeType: " + type);
  }

  public static String toJsonStr(List<?> attributeValue) {
    StringJoiner joiner = new StringJoiner(",", "[", "]");
    for (int i = 0; i < attributeValue.size(); i++) {
      Object value = attributeValue.get(i);
      joiner.add(value instanceof String ? toJsonValidStr((String) value) : String.valueOf(value));
    }
    return joiner.toString();
  }

  public static String toJsonValidStr(String str) {
    StringBuilder sb = new StringBuilder();
    sb.append('"');
    for (int i = 0; i < str.length(); i++) {
      char c = str.charAt(i);