# HG changeset patch # User František Kučera # Date 1416244347 -3600 # Node ID 4819598eb6237c1bc56d5ad7d208cad206a29440 # Parent 8e99832606245ee19dc9ab5a891f2021a10d7bc9 custom console colorful logger diff -r 8e9983260624 -r 4819598eb623 java/copy-image-resizer/src/cz/frantovo/copyImageResizer/logging/ColorfulConsoleFormatter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/copy-image-resizer/src/cz/frantovo/copyImageResizer/logging/ColorfulConsoleFormatter.java Mon Nov 17 18:12:27 2014 +0100 @@ -0,0 +1,100 @@ +/** + * copy-image-resizer + * Copyright © 2013 František Kučera (frantovo.cz) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cz.frantovo.copyImageResizer.logging; + +import cz.frantovo.copyImageResizer.logging.ColorfulPrintWriter.TerminalColor; +import cz.frantovo.copyImageResizer.logging.ColorfulPrintWriter.TerminalStyle; +import java.io.StringWriter; +import java.util.logging.Formatter; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +/** + * For console/terminal log output. Log messages are printed in brief and colorful form. + * + * @author Ing. František Kučera (frantovo.cz) + */ +public class ColorfulConsoleFormatter extends Formatter { + + private boolean printStacktrace = false; + + @Override + public String format(LogRecord r) { + StringWriter sw = new StringWriter(); + try (ColorfulPrintWriter out = new ColorfulPrintWriter(sw)) { + printLevel(out, r.getLevel()); + printMessage(out, r); + printThrowable(out, r); + out.println(); + } + return sw.toString(); + } + + private void printLevel(ColorfulPrintWriter out, Level l) { + TerminalColor color = TerminalColor.Magenta; + + if (l == Level.SEVERE) { + color = TerminalColor.Red; + } else if (l == Level.WARNING) { + color = TerminalColor.Yellow; + } + + out.print(color, rpad(l.getLocalizedName() + ": ", 10)); + } + + private void printMessage(ColorfulPrintWriter out, LogRecord r) { + out.print(formatMessage(r)); + } + + private void printThrowable(ColorfulPrintWriter out, LogRecord r) { + Throwable t = r.getThrown(); + if (t != null) { + out.print(": "); + out.print(TerminalColor.Red, t.getClass().getSimpleName()); + String message = t.getLocalizedMessage(); + if (message != null) { + out.print(": "); + out.print(message); + } + if (printStacktrace) { + out.println(); + out.setForegroundColor(TerminalColor.Yellow); + out.setStyle(TerminalStyle.Dim); + t.printStackTrace(out); + out.resetAll(); + } + } + } + + public boolean isPrintStacktrace() { + return printStacktrace; + } + + public void setPrintStacktrace(boolean printStacktrace) { + this.printStacktrace = printStacktrace; + } + + private static String rpad(String s, int n) { + if (n > 0) { + return String.format("%1$-" + n + "s", s); + } else { + return s; + } + } + +} diff -r 8e9983260624 -r 4819598eb623 java/copy-image-resizer/src/cz/frantovo/copyImageResizer/logging/ColorfulPrintWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/copy-image-resizer/src/cz/frantovo/copyImageResizer/logging/ColorfulPrintWriter.java Mon Nov 17 18:12:27 2014 +0100 @@ -0,0 +1,358 @@ +/** + * copy-image-resizer + * Copyright © 2013 František Kučera (frantovo.cz) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cz.frantovo.copyImageResizer.logging; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.util.EnumSet; + +/** + * PrintWriter with convenience methods for printing color and formatted text. + * + * Uses ANSI Escape Sequences. + * See: http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html + * + * @author Ing. František Kučera (frantovo.cz) + */ +public class ColorfulPrintWriter extends PrintWriter { + + public enum TerminalColor { + + Black(30, 40), + Red(31, 41), + Green(32, 42), + Yellow(33, 43), + Blue(34, 44), + Magenta(35, 45), + Cyan(36, 46), + White(37, 47); + private final int foregroundCode; + private final int backgroundCode; + + private TerminalColor(int foregroundCode, int backgroundCode) { + this.foregroundCode = foregroundCode; + this.backgroundCode = backgroundCode; + } + + public int getForegroundCode() { + return foregroundCode; + } + + public int getBackgroundCode() { + return backgroundCode; + } + } + + public enum TerminalStyle { + + Reset(0), + Bright(1), + Dim(2), + Underscore(4), + Blink(5), + Reverse(7), + Hidden(8); + private int code; + + private TerminalStyle(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + } + private final boolean COLOR_ENABLED; + private boolean colorful = true; + + public void setStyle(TerminalStyle style) { + setStyle(EnumSet.of(style)); + } + + public void setStyle(EnumSet styles) { + printCodes(getStyleCodes(styles)); + } + + private static int[] getStyleCodes(EnumSet styles) { + int[] array = new int[styles.size()]; + int i = 0; + for (TerminalStyle s : styles) { + array[i++] = s.getCode(); + } + return array; + } + + /** + * Print (usually audible) bell code (\007, \a, ^G) + */ + public void bell() { + print("\007"); + } + + /** + * Eat the last character + */ + public void backspace() { + print("\b"); + } + + /** + * Eat n last characters + * + * @param count n + */ + public void backspace(int count) { + for (int i = 0; i < count; i++) { + backspace(); + } + } + + /** + * With 100 ms delay and all colors. + * + * @see #printRainbow(java.lang.String, int, + * info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor[]) + */ + public void printRainbow(String string) { + printRainbow(string, 100); + } + + /** + * With all colors. + * + * @see #printRainbow(java.lang.String, int, + * info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor[]) + */ + public void printRainbow(String string, int delay) { + printRainbow(string, delay, TerminalColor.values()); + } + + /** + * Prints rainbow text – (re)writes same text subsequently in given colors and then in default + * color. + * + * @param string text to be printed, should not contain \n new line (then rainbow does not work + * – use println() after printRainbow() instead) + * @param delay delay between rewrites + * @param colors list of colors to be used + */ + public void printRainbow(String string, int delay, TerminalColor... colors) { + for (TerminalColor c : colors) { + print(c, string); + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + // no time to sleep + break; + } + backspace(string.length()); + flush(); + } + print(string); + } + + public void setForegroundColor(TerminalColor color) { + printCodes(color.getForegroundCode()); + } + + public void setBackgroundColor(TerminalColor color) { + printCodes(color.getBackgroundCode()); + } + + public void print(TerminalColor foregroundColor, String string) { + setForegroundColor(foregroundColor); + print(string); + resetAll(); + } + + public void println(TerminalColor foregroundColor, String string) { + print(foregroundColor, string); + println(); + } + + public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, String string) { + setForegroundColor(foregroundColor); + setBackgroundColor(backgroundColor); + print(string); + resetAll(); + } + + public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, String string) { + print(foregroundColor, backgroundColor, string); + println(); + } + + public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, EnumSet styles, String string) { + setForegroundColor(foregroundColor); + setBackgroundColor(backgroundColor); + setStyle(styles); + print(string); + resetAll(); + } + + public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, EnumSet styles, String string) { + print(foregroundColor, backgroundColor, styles, string); + println(); + } + + public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, TerminalStyle style, String string) { + print(foregroundColor, backgroundColor, EnumSet.of(style), string); + } + + public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, TerminalStyle style, String string) { + print(foregroundColor, backgroundColor, style, string); + println(); + } + + public void print(TerminalColor foregroundColor, EnumSet styles, String string) { + setForegroundColor(foregroundColor); + setStyle(styles); + print(string); + resetAll(); + } + + public void println(TerminalColor foregroundColor, EnumSet styles, String string) { + print(foregroundColor, styles, string); + println(); + } + + public void print(TerminalColor foregroundColor, TerminalStyle style, String string) { + print(foregroundColor, EnumSet.of(style), string); + } + + public void println(TerminalColor foregroundColor, TerminalStyle style, String string) { + print(foregroundColor, style, string); + println(); + } + + public void print(EnumSet styles, String string) { + setStyle(styles); + print(string); + resetAll(); + } + + public void println(EnumSet styles, String string) { + print(styles, string); + println(); + } + + public void print(TerminalStyle style, String string) { + print(EnumSet.of(style), string); + } + + public void println(TerminalStyle style, String string) { + print(style, string); + println(); + } + + public void resetAll() { + printCodes(TerminalStyle.Reset.code); + } + + private void printCodes(int... codes) { + if (COLOR_ENABLED && colorful) { + print("\033["); + for (int i = 0; i < codes.length; i++) { + print(codes[i]); + if (i < codes.length - 1 && codes.length > 1) { + print(";"); + } + } + print("m"); + } + } + + /** + * Colors can be switched on/off during usage of this writer. + * + * @return whether colors are currently turned on + * @see #isColorEnabled() + */ + public boolean isColorful() { + return colorful; + } + + /** + * Collors might be definitively disabled in constructor. If not, they can be turned on/off + * during usage of this writer by {@linkplain #setColorful(boolean)} + * + * @return whether colors are allowed for this instance of this class + * @see #isColorful() + */ + public boolean isColorEnabled() { + return COLOR_ENABLED; + } + + /** + * @see #isColorful() + * @see #isColorEnabled() + */ + public void setColorful(boolean colorful) { + this.colorful = colorful; + } + + public ColorfulPrintWriter(File file) throws FileNotFoundException { + super(file); + COLOR_ENABLED = true; + } + + public ColorfulPrintWriter(OutputStream out) { + super(out); + COLOR_ENABLED = true; + } + + public ColorfulPrintWriter(String fileName) throws FileNotFoundException { + super(fileName); + COLOR_ENABLED = true; + } + + public ColorfulPrintWriter(Writer out) { + super(out); + COLOR_ENABLED = true; + } + + public ColorfulPrintWriter(File file, String csn) throws FileNotFoundException, UnsupportedEncodingException { + super(file, csn); + COLOR_ENABLED = true; + } + + /** + * @param colorEnabled colors might be definitively disabled by this option – this might be more + * optimalizable than dynamic turning off colors by {@linkplain #setColorful(boolean)} which is + * not definitive (colors can be turned on during live of this instance). This might be useful + * if you need an instance of this class but don't need colors at all. + */ + public ColorfulPrintWriter(OutputStream out, boolean autoFlush, boolean colorEnabled) { + super(out, autoFlush); + COLOR_ENABLED = colorEnabled; + } + + public ColorfulPrintWriter(String fileName, String csn) throws FileNotFoundException, UnsupportedEncodingException { + super(fileName, csn); + COLOR_ENABLED = true; + } + + public ColorfulPrintWriter(Writer out, boolean autoFlush) { + super(out, autoFlush); + COLOR_ENABLED = true; + } +} diff -r 8e9983260624 -r 4819598eb623 java/copy-image-resizer/src/cz/frantovo/copyImageResizer/logging/ConsoleLoggerInitializer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/copy-image-resizer/src/cz/frantovo/copyImageResizer/logging/ConsoleLoggerInitializer.java Mon Nov 17 18:12:27 2014 +0100 @@ -0,0 +1,78 @@ +/** + * copy-image-resizer + * Copyright © 2013 František Kučera (frantovo.cz) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cz.frantovo.copyImageResizer.logging; + +import cz.frantovo.copyImageResizer.Constants; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Configures logging subsystem. + * Usage: java -Djava.util.logging.config.class=info.globalcode.sql.dk.logging.ConsoleLoggerInitializer … + * + * @author Ing. František Kučera (frantovo.cz) + */ +public class ConsoleLoggerInitializer { + + private static final Logger log = Logger.getLogger(ConsoleLoggerInitializer.class.getName()); + public static final String LEVEL_PROPERTY = ConsoleLoggerInitializer.class.getName() + ".level"; + private static final Level DEFAULT_LEVEL = Level.INFO; + + public ConsoleLoggerInitializer() { + Logger logger = Logger.getLogger(Constants.JAVA_PACKAGE); + ConsoleHandler handler = new ConsoleHandler(); + ColorfulConsoleFormatter formatter = new ColorfulConsoleFormatter(); + + logger.addHandler(handler); + handler.setFormatter(formatter); + + setLevel(logger, handler, formatter); + + + /** + * TODO: optional FileHandler – detailed logs in file in ~/sql-dk/log/… + */ + } + + private void setLevel(Logger logger, Handler handler, ColorfulConsoleFormatter formatter) { + boolean levelParseError = false; + Level level; + String cliLevel = System.getProperty(LEVEL_PROPERTY); + if (cliLevel == null) { + level = DEFAULT_LEVEL; + } else { + try { + level = Level.parse(cliLevel); + } catch (IllegalArgumentException e) { + level = DEFAULT_LEVEL; + levelParseError = true; + } + } + + handler.setLevel(level); + logger.setLevel(level); + + if (levelParseError) { + log.log(Level.WARNING, "Invalid logging level „{0}“ specified in „{1}“ → using default level „{2}“", new Object[]{cliLevel, LEVEL_PROPERTY, DEFAULT_LEVEL}); + } + + formatter.setPrintStacktrace(level.intValue() < Level.INFO.intValue()); + } +}