/*
* Copyright 2015 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.linecorp.armeria.common.util;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
/**
* A utility class to format things as a {@link String} with ease.
*/
public final class TextFormatter {
private TextFormatter() {}
/**
* Appends the human-readable representation of the specified byte-unit {@code size} to the specified
* {@link StringBuffer}.
*/
public static void appendSize(StringBuilder buf, long size) {
if (size >= 104857600) { // >= 100 MiB
buf.append(size / 1048576).append("MiB(").append(size).append("B)");
} else if (size >= 102400) { // >= 100 KiB
buf.append(size / 1024).append("KiB(").append(size).append("B)");
} else {
buf.append(size).append('B');
}
}
/**
* Appends the human-readable representation of the duration given as {@code elapsed} to the specified
* {@link StringBuilder}.
*/
public static void appendElapsed(StringBuilder buf, long elapsedNanos) {
if (elapsedNanos >= 100000000000L) { // >= 100 s
buf.append(elapsedNanos / 1000000000L).append("s(").append(elapsedNanos).append("ns)");
} else if (elapsedNanos >= 100000000L) { // >= 100 ms
buf.append(elapsedNanos / 1000000L).append("ms(").append(elapsedNanos).append("ns)");
} else if (elapsedNanos >= 100000L) { // >= 100 us
buf.append(elapsedNanos / 1000L).append("\u00B5s(").append(elapsedNanos).append("ns)"); // microsecs
} else {
buf.append(elapsedNanos).append("ns");
}
}
/**
* Appends the human-readable representation of the duration between the specified {@code startTimeNanos}
* and {@code endTimeNanos} to the specified {@link StringBuilder}.
*/
public static void appendElapsed(StringBuilder buf, long startTimeNanos, long endTimeNanos) {
appendElapsed(buf, endTimeNanos - startTimeNanos);
}
/**
* A shortcut method that calls {@link #appendElapsed(StringBuilder, long, long)} and
* {@link #appendSize(StringBuilder, long)}, concatenated by {@code ", "}.
*/
public static void appendElapsedAndSize(
StringBuilder buf, long startTimeNanos, long endTimeNanos, long size) {
appendElapsed(buf, startTimeNanos, endTimeNanos);
buf.append(", ");
appendSize(buf, size);
}
/**
* Creates a new {@link StringBuilder} whose content is the human-readable representation of the duration
* given as {@code elapsed}.
*/
public static StringBuilder elapsed(long elapsedNanos) {
final StringBuilder buf = new StringBuilder(16);
appendElapsed(buf, elapsedNanos);
return buf;
}
/**
* Creates a new {@link StringBuilder} whose content is the human-readable representation of the duration
* between the specified {@code startTimeNanos} and {@code endTimeNanos}.
*/
public static StringBuilder elapsed(long startTimeNanos, long endTimeNanos) {
return elapsed(endTimeNanos - startTimeNanos);
}
/**
* Creates a new {@link StringBuilder} whose content is the human-readable representation of the byte-unit
* {@code size}.
*/
public static StringBuilder size(long size) {
final StringBuilder buf = new StringBuilder(16);
appendSize(buf, size);
return buf;
}
/**
* Similar to {@link #appendElapsedAndSize(StringBuilder, long, long, long)} except that this method
* creates a new {@link StringBuilder}.
*/
public static StringBuilder elapsedAndSize(long startTimeNanos, long endTimeNanos, long size) {
final StringBuilder buf = new StringBuilder(16);
appendElapsedAndSize(buf, startTimeNanos, endTimeNanos, size);
return buf;
}
private static final DateTimeFormatter dateTimeFormatter =
new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
.toFormatter(Locale.ENGLISH)
.withZone(ZoneId.of("GMT"));
/**
* Formats the given epoch time to typical human-readable format "yyyy-MM-dd'T'HH_mm:ss.SSSX" and appends
* it to the specified {@link StringBuilder}.
*/
public static void appendEpoch(StringBuilder buf, long timeMillis) {
buf.append(dateTimeFormatter.format(Instant.ofEpochMilli(timeMillis)))
.append('(').append(timeMillis).append(')');
}
/**
* Formats the given epoch time to typical human-readable format "yyyy-MM-dd'T'HH:mm:ss.SSSX"
*
* @param timeMillis epoch time in ms
*
* @return the human readable string representation of the given epoch time
*/
public static StringBuilder epoch(long timeMillis) {
// 24 (human readable part) + 3 (parens) + 19 (max digits of a long integer)
final StringBuilder buf = new StringBuilder(46);
appendEpoch(buf, timeMillis);
return buf;
}
}