All Downloads are FREE. Search and download functionalities are using the official Maven repository.

blasd.apex.core.logging.ApexLogHelper Maven / Gradle / Ivy

The newest version!
/**
 * The MIT License
 * Copyright (c) 2014 Benoit Lacelle
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package blasd.apex.core.logging;

import java.text.DecimalFormat;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;

import blasd.apex.core.memory.IApexMemoryConstants;

/**
 * Various helpers for logging
 * 
 * @author Benoit Lacelle
 *
 */
public class ApexLogHelper {
	private static final long HUNDRED = 100L;

	/**
	 * We want to see at least 2 digits: after printing 9999B, we print 10KB
	 */
	protected static final int BARRIER_FOR_SIZE_IN_LOG = 10;

	public static final int THOUSAND = 1000;
	public static final int TEN_F = 10;

	private static final long LIMIT_ENTRY_PER_XXX = 10;

	protected ApexLogHelper() {
		// hidden
	}

	/**
	 * This methods facilitates using logging framework at trace level, without using .isTraceEnabled, as the .toString
	 * 
	 * @param toStringMe
	 *            the object from which a .toString should be computed lazily
	 * @return an Object which has as .toString the one provided by the Supplier
	 */
	public static Object lazyToString(Supplier toStringMe) {
		return new Object() {
			@Override
			public String toString() {
				return toStringMe.get();
			}
		};
	}

	public static Object getNicePercentage(long progress, long max) {
		return lazyToString(() -> {
			if (progress < 0L || max <= 0L) {
				return "-%";
			} else {
				long ratio = progress * HUNDRED / max;

				if (ratio == 0) {
					long smallRatio = progress * THOUSAND / max;

					if (smallRatio == 0) {
						long verySmallRatio = progress * HUNDRED * HUNDRED / max;
						return "0.0" + Long.toString(verySmallRatio) + "%";
					} else {
						return "0." + Long.toString(smallRatio) + "%";
					}
				} else if (ratio < TEN_F) {
					long smallRatio = (progress - ratio * TEN_F) * THOUSAND / max;

					// We prefer having at least 2 digits
					return ratio + "." + Long.toString(smallRatio) + "%";
				} else {
					return Long.toString(ratio) + "%";
				}
			}
		});
	}

	public static Object getNiceMemory(long size) {
		return lazyToString(() -> {
			long absSize = Math.abs(size);
			if (absSize < BARRIER_FOR_SIZE_IN_LOG * IApexMemoryConstants.KB) {
				return size + "B";
			} else if (absSize < BARRIER_FOR_SIZE_IN_LOG * IApexMemoryConstants.MB) {
				return (size / IApexMemoryConstants.KB) + "KB";
			} else if (absSize < BARRIER_FOR_SIZE_IN_LOG * IApexMemoryConstants.GB) {
				return (size / IApexMemoryConstants.MB) + "MB";
			} else if (absSize < BARRIER_FOR_SIZE_IN_LOG * IApexMemoryConstants.TB) {
				return (size / IApexMemoryConstants.GB) + "GB";
			} else {
				return (size / IApexMemoryConstants.TB) + "TB";
			}
		});
	}

	public static Object getObjectAndClass(Object o) {
		return lazyToString(() -> {
			if (o == null) {
				return null + "(null)";
			} else {
				return o.toString() + "(" + o.getClass().getName() + ")";
			}
		});
	}

	/**
	 * @deprecated prefer .getFirstChars
	 */
	@Deprecated
	public static Object getToStringWithLimit(Iterable iterable, int limitSize) {
		return lazyToString(() -> {
			if (iterable == null) {
				return null + "(null)";
			} else {
				int size = Iterables.size(iterable);

				if (size <= limitSize) {
					return iterable.toString();
				} else {
					// Iterable limited = Iterables.limit(iterable, limitSize);

					return "[" + Streams.stream(iterable).limit(limitSize).map(Object::toString).collect(
							Collectors.joining(", ")) + ", (" + (size - limitSize) + " more elements)]";
				}
			}
		});
	}

	public static Object getNiceDouble(Double value) {
		if (value == null) {
			return "null";
		} else {
			return lazyToString(() -> {
				final String pattern = ".##";
				// final String pattern = "###,###,##0.00";
				final DecimalFormat myFormatter = new DecimalFormat(pattern);

				return myFormatter.format(value);
			});
		}
	}

	public static Object getNiceTime(long timeInMs) {
		return getNiceTime(timeInMs, TimeUnit.MILLISECONDS);
	}

	private static final String HOURS_PREFIX = "hours";
	private static final String MINUTES_PREFIX = "min";
	private static final String SECONDS_PREFIX = "sec";
	private static final String MILLIS_PREFIX = "ms";

	public static Object getNiceTime(long time, TimeUnit timeUnit) {
		return ApexLogHelper.lazyToString(() -> {
			long timeInMs = timeUnit.toMillis(time);

			if (timeInMs >= TimeUnit.HOURS.toMillis(1)) {
				String minString = TimeUnit.MILLISECONDS.toHours(timeInMs) + HOURS_PREFIX;

				long minutes = timeInMs - TimeUnit.HOURS.toMillis(1) * TimeUnit.MILLISECONDS.toHours(timeInMs);

				if (minutes > 0) {
					return minString + " " + TimeUnit.MILLISECONDS.toMinutes(minutes) + MINUTES_PREFIX;
				} else {
					return minString;
				}
			} else if (timeInMs >= TimeUnit.MINUTES.toMillis(1)) {
				String minString = TimeUnit.MILLISECONDS.toMinutes(timeInMs) + MINUTES_PREFIX;

				long seconds = timeInMs - TimeUnit.MINUTES.toMillis(1) * TimeUnit.MILLISECONDS.toMinutes(timeInMs);

				if (seconds > 0) {
					return minString + " " + TimeUnit.MILLISECONDS.toSeconds(seconds) + SECONDS_PREFIX;
				} else {
					return minString;
				}

			} else if (timeInMs >= TimeUnit.SECONDS.toMillis(1)) {
				String minString = TimeUnit.MILLISECONDS.toSeconds(timeInMs) + SECONDS_PREFIX;

				long millis = timeInMs - TimeUnit.SECONDS.toMillis(1) * TimeUnit.MILLISECONDS.toSeconds(timeInMs);

				if (millis > 0) {
					return minString + " " + millis + MILLIS_PREFIX;
				} else {
					return minString;
				}
			} else {
				return timeInMs + MILLIS_PREFIX;
			}
		});
	}

	public static Object getNiceRate(long nbEntries, long time, TimeUnit timeUnit) {
		return lazyToString(() -> {
			if (time <= 0) {
				// Edge case
				return nbEntries + "#/0" + timeUnit;
			}

			// We prefer rate per second, without any /
			long entryPerSecond = TimeUnit.SECONDS.convert(nbEntries / time, timeUnit);

			if (entryPerSecond > LIMIT_ENTRY_PER_XXX) {
				// if rate is too high, we switch to rate per minute
				long entryPerMinute = TimeUnit.MINUTES.convert(nbEntries / time, timeUnit);

				if (entryPerMinute > LIMIT_ENTRY_PER_XXX) {
					// Rate per minute is high enough: stick to it
					return entryPerMinute + "#/" + MINUTES_PREFIX;
				} else {
					// Rate per second is nice
					return entryPerSecond + "#/" + SECONDS_PREFIX;
				}
			} else {
				long nbSeconds = TimeUnit.SECONDS.convert(time, timeUnit);

				if (nbSeconds > 0) {
					// The window is 1 second wide
					long entryPerSecond2 = nbEntries / nbSeconds;

					return entryPerSecond2 + "#/" + SECONDS_PREFIX;
				} else {
					// The window is not 1 second wide: it can safely be turned to nanos
					long entryPerNano = TimeUnit.NANOSECONDS.convert(nbEntries, timeUnit) / time;

					long entryPerSecond2 = TimeUnit.SECONDS.convert(entryPerNano, TimeUnit.NANOSECONDS);

					if (entryPerSecond2 > 0) {
						// Rate per second is nice
						return entryPerSecond2 + "#/" + SECONDS_PREFIX;
					} else {
						long entryPerMillis = TimeUnit.MILLISECONDS.convert(entryPerNano, TimeUnit.NANOSECONDS);
						return entryPerMillis + "#/" + MILLIS_PREFIX;
					}
				}
				//
				// // Rate per second is too low: switch to rate per millis
				// long entryPerMillis = nbEntries / TimeUnit.MILLISECONDS.convert(time, timeUnit);
				//
				// if (entryPerMillis >= 0) {
				// return entryPerMillis + "#/ms";
				// } else {
				//
				// }
			}
		});
	}

	public static Object getFirstChars(Object toString, int limitChars) {
		return lazyToString(() -> {
			String asString = toString.toString();
			if (asString.length() <= limitChars) {
				return asString;
			} else {
				return "'" + asString.substring(0, limitChars)
						+ "...("
						+ (asString.length() - limitChars)
						+ " more chars)'";
			}
		});
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy