001package io.prometheus.metrics.expositionformats; 002 003import io.prometheus.metrics.model.snapshots.Labels; 004import java.io.IOException; 005import java.io.Writer; 006 007public class TextFormatUtil { 008 009 static void writeLong(Writer writer, long value) throws IOException { 010 writer.append(Long.toString(value)); 011 } 012 013 static void writeDouble(Writer writer, double d) throws IOException { 014 if (d == Double.POSITIVE_INFINITY) { 015 writer.write("+Inf"); 016 } else if (d == Double.NEGATIVE_INFINITY) { 017 writer.write("-Inf"); 018 } else { 019 writer.write(Double.toString(d)); 020 // FloatingDecimal.getBinaryToASCIIConverter(d).appendTo(writer); 021 } 022 } 023 024 static void writeTimestamp(Writer writer, long timestampMs) throws IOException { 025 writer.write(Long.toString(timestampMs / 1000L)); 026 writer.write("."); 027 long ms = timestampMs % 1000; 028 if (ms < 100) { 029 writer.write("0"); 030 } 031 if (ms < 10) { 032 writer.write("0"); 033 } 034 writer.write(Long.toString(ms)); 035 } 036 037 static void writeEscapedLabelValue(Writer writer, String s) throws IOException { 038 // optimize for the common case where no escaping is needed 039 int start = 0; 040 // #indexOf is a vectorized intrinsic 041 int backslashIndex = s.indexOf('\\', start); 042 int quoteIndex = s.indexOf('\"', start); 043 int newlineIndex = s.indexOf('\n', start); 044 045 int allEscapesIndex = backslashIndex & quoteIndex & newlineIndex; 046 while (allEscapesIndex != -1) { 047 int escapeStart = Integer.MAX_VALUE; 048 if (backslashIndex != -1) { 049 escapeStart = backslashIndex; 050 } 051 if (quoteIndex != -1) { 052 escapeStart = Math.min(escapeStart, quoteIndex); 053 } 054 if (newlineIndex != -1) { 055 escapeStart = Math.min(escapeStart, newlineIndex); 056 } 057 058 // bulk write up to the first character that needs to be escaped 059 if (escapeStart > start) { 060 writer.write(s, start, escapeStart - start); 061 } 062 char c = s.charAt(escapeStart); 063 start = escapeStart + 1; 064 switch (c) { 065 case '\\': 066 writer.write("\\\\"); 067 backslashIndex = s.indexOf('\\', start); 068 break; 069 case '\"': 070 writer.write("\\\""); 071 quoteIndex = s.indexOf('\"', start); 072 break; 073 case '\n': 074 writer.write("\\n"); 075 newlineIndex = s.indexOf('\n', start); 076 break; 077 } 078 079 allEscapesIndex = backslashIndex & quoteIndex & newlineIndex; 080 } 081 // up until the end nothing needs to be escaped anymore 082 int remaining = s.length() - start; 083 if (remaining > 0) { 084 writer.write(s, start, remaining); 085 } 086 } 087 088 static void writeLabels( 089 Writer writer, Labels labels, String additionalLabelName, double additionalLabelValue) 090 throws IOException { 091 writer.write('{'); 092 for (int i = 0; i < labels.size(); i++) { 093 if (i > 0) { 094 writer.write(","); 095 } 096 writer.write(labels.getPrometheusName(i)); 097 writer.write("=\""); 098 writeEscapedLabelValue(writer, labels.getValue(i)); 099 writer.write("\""); 100 } 101 if (additionalLabelName != null) { 102 if (!labels.isEmpty()) { 103 writer.write(","); 104 } 105 writer.write(additionalLabelName); 106 writer.write("=\""); 107 writeDouble(writer, additionalLabelValue); 108 writer.write("\""); 109 } 110 writer.write('}'); 111 } 112}