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

com.sta.mlogger.MLogger Maven / Gradle / Ivy

There is a newer version: 1.11
Show newest version

package com.sta.mlogger;

import java.util.Properties;
import java.util.Stack;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.function.BiConsumer;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;

import com.sta.mutils.ThrowingRunnable;

/**
 * 

Name: MLogger

*

Description: Realisierung einer Logger-Schnittstelle f?r diverse Projekte. * Gedacht ist diese Klasse als eine zentrale Stelle f?r alle Logging-Aktionen. * Durch die Registration von MLogEntries kann je nach den Anforderungen im * konkreten Projekt ein anderer (realer) Logger verwendet werden. Der * einfachste Fall ist in MLogEntry4Text gezeigt. Hier wird einfach ein * PrintWriter zur Ausgabe verwendet. Soll z. B. ein Standard-Logger benutzt * werden (k?nnte die Variante von Apache sein), mu? lediglich ein * MLogEntry4xxx (abgeleitet von MLogEntry) erzeugt werden, der im einfachsten * Fall nur die Methode MLogEntry.println(String) ?berschreibt. Eine Instanz * dieses MLogEntry4xxx ist dann beim Programmstart (vor der ersten * Logging-Aktion) beim Logger zu registrieren (addMLogEntry(MLogEntry)). Falls * bei der ersten Logging-Aktion (noch) kein MLogEntry registriert wurde, * wird ein Standard-MLogEntry (MLogEntry4Text) erzeugt und registriert. * Beim Logger k?nnen (wie bereits beschrieben) auch mehrere MLogEntries * registriert werden. Alle Logging-Aktionen werden dann an alle registrierten * MLogEntries weitergeleitet. Somit sind diese daf?r verantwortlich, * entsprechend dem LogLevel eine Selektion vorzunehmen. Die Standard-Methoden * in der Basisklasse MLogEntry bieten daf?r bereits die notwendige * Unterst?tzung. * Ab Version 1.01 wird die Ausgabe ohne Zeilenumbruch nicht mehr unterst?tzt. * Mit Version 1.21 erfolgte die Umstellung auf Java 1.8 (ff.) und erstmalige * Verwendung einer Lambda-Konstruktion, um den Text f?r auszugebende * Nachrichten erst dann zu erstellen, wenn dieser tats?chlich ben?tigt wird. * Mit Version 1.26 wird die optionale Verwendung eines Thread-Contexts als * "MDC" (Mapped Diagnostic Context) umgesetzt. * Mit Version 1.27 erfolgt die Umstellung auf Maven. * Mit Version 1.32 erfolgt die Verteilung ?ber Maven-Central. *

*

Copyright: Copyright (c) 2002-2014, 2017-2021

*

Company: >StA-Soft<

* @author StA * @version 1.38 */ public class MLogger { /** * MLogger-Version. */ public static final String VERSION = MLoggerVersionHelper.VERSION; /** * Copyright. */ public static final String COPYRIGHT = MLoggerVersionHelper.COPYRIGHT; /** * Firma. */ public static final String COMPANY = MLoggerVersionHelper.COMPANY; /** * Name des MLogger-Property-Files. */ private static final String PROP_FILENAME = "mlogger.properties"; /** * Name des optionalen System-Propertys f?r das Verzeichnis des MLogger-Property-Files. */ public static final String SYSTEM_PROPERTY_NAME = "mlogger.config.dir"; /** * Menge der registrierten MLogEntries, die f?r alle Threads gelten, f?r die * keine speziellen MLogEntries definiert wurden. */ private static Vector statMLogEntries = new Vector(); /** * Hash-Tabelle mit Vektoren mit MLogEntries, die f?r einen konkreten Thread * definiert sind. Schl?ssel ist der Thread-Name oder die Thread-Id. */ private static Hashtable statThreadEntries = new Hashtable(); /** * Maximale Anzahl an Eintr?gen in einem Stack. */ private static final int MAX_THREAD_STACK_SIZE = 100; /** * Zeitpunkt der letzten F?llstands?berpr?fung ?ber alle Stacks. */ private static long statLastFullCheck = 0; /** * Hash-Tabelle mit Stacks f?r Log-Schl?ssel zur Zeitmessung von der * Start-Log-Meldung bis zum "Ok" bzw. "Error". */ private static Hashtable statThreadStacks = new Hashtable(); //=========================================================================== /** * Eintrag in einem Stack. */ private static class ThreadStackEntry { /** * Text. */ private String myText; /** * Zeit. */ private long myTime; /** * Constructor mit Text. * @param pText Text */ protected ThreadStackEntry(String pText) { myText = pText; myTime = System.currentTimeMillis(); } /** * Text ermitteln. * @return Text */ public String getText() { return myText; } /** * Zeit ermitteln. * @return Zeit */ public long getTime() { return myTime; } } //=========================================================================== /** * Version ermitteln. * @return Version */ public static String getVersion() { return VERSION; } /** * Copyright ermitteln. * @return Copyright */ public static String getCopyright() { return COPYRIGHT; } /** * Company ermitteln. * @return Company */ public static String getCompany() { return COMPANY; } //=========================================================================== /** * String f?r Einr?ckung liefern. Die Methode wurde u. a. deshalb hier * eingef?hrt und als "static" deklariert, damit sie auch von anderen Klassen * m?glichst einfach verwendet werden kann. * @param indent Anzahl der Leerzeichen * @return String aus vorgegebener Anzahl von Leerzeichen * @see #indentStrg(String, int) */ public static String indent(int indent) { StringBuilder sb = new StringBuilder(indent); for (int i = 0; i < indent; i++) { sb.append(' '); } return sb.toString(); } /** * String pStrg pro Zeile (!) um indent Leerzeichen einr?cken. Zeilenenden * werden also beachtet. Auch diese Methode wurde u. a. deshalb hier * eingef?hrt und als "static" deklariert, damit sie auch von anderen Klassen * m?glichst einfach verwendet werden kann. * @param pStrg der String, der zeilenweise "einger?ckt" werden soll * @param indent Anzahl der Leerzeichen * @return Ergebnis-String * @see #indent(int) */ public static String indentStrg(String pStrg, int indent) { StringBuilder sb = new StringBuilder(); String si = indent(indent); StringTokenizer st = new StringTokenizer(pStrg, "\n\r"); while (st.hasMoreTokens()) { sb.append(si).append(st.nextToken()).append('\n'); } return sb.toString(); } //--------------------------------------------------------------------------- /** * MLogEntry registrieren bzw. hinzuf?gen. * @param pMLogEntry ein initialisierter MLogEntry */ public static synchronized void addMLogEntry(MLogEntry pMLogEntry) { statMLogEntries.add(pMLogEntry); } /** * Anzahl der schon vorhandenen MLogEntries ermitteln. * @return die Anzahl */ public static synchronized int getMLogEntryCount() { return statMLogEntries.size(); } /** * MLogEntry an Index i ermitteln. * @param i der Index * @return der MLogEntry */ public static synchronized MLogEntry getMLogEntry(int i) { return (MLogEntry) statMLogEntries.get(i); } /** * MLogEntries als Enumeration ermitteln. * @return Enumeration der MLogEntries */ public static synchronized Enumeration getMLogEntries() { return statMLogEntries.elements(); } /** * MLogEntry an Index i entfernen. * @param i der Index */ public static synchronized void removeMLogEntry(int i) { statMLogEntries.remove(i); } /** * MLogEntry entfernen. * @param pMLogEntry ein MLogEntry, der bereits enthalten ist */ public static synchronized void removeMLogEntry(MLogEntry pMLogEntry) { statMLogEntries.remove(pMLogEntry); } //--------------------------------------------------------------------------- /** * Thread-Eintrag ermitteln. * @return Thread-Eintrag */ private static Vector getThreadEntry() { String key = Thread.currentThread().getName(); return (Vector) statThreadEntries.get(key); } /** * Pr?fen ob Thread-Eintrag vorhanden, falls nicht: anlegen. * @return Thread-Eintrag */ private static Vector checkThreadEntry() { String key = Thread.currentThread().getName(); Vector v = (Vector) statThreadEntries.get(key); if (v == null) { v = new Vector(); statThreadEntries.put(key, v); } return v; } /** * MLogEntry registrieren bzw. hinzuf?gen (thread-spezifisch). * @param pMLogEntry ein initialisierter MLogEntry */ public static synchronized void addMLogEntryTS(MLogEntry pMLogEntry) { Vector v = checkThreadEntry(); v.add(pMLogEntry); } /* public static synchronized void addMLogEntryTSx(MLogEntry pMLogEntry) { // Pr?fe, ob ein solche MLogEntry bereits (Thread-spezifisch) hinzugef?gt // wurde. Falls ja: f?ge eben diesen statt dem ?bergebenen erneut hinzu. Enumeration e = statThreadEntries.elements(); while (e.hasMoreElements()) { Vector vv = (Vector) e.nextElement(); int i = vv.indexOf(pMLogEntry); if (i >= 0) { pMLogEntry = (MLogEntry) vv.get(i); break; } } Vector v = checkThreadEntry(); v.add(pMLogEntry); } */ /** * Anzahl der schon vorhandenen MLogEntries ermitteln (thread-spezifisch). * @return die Anzahl */ public static synchronized int getMLogEntryCountTS() { Vector v = getThreadEntry(); return v != null ? v.size() : 0; } /** * MLogEntry an Index i ermitteln (thread-spezifisch). * @param i der Index * @return der MLogEntry */ public static synchronized MLogEntry getMLogEntryTS(int i) { Vector v = getThreadEntry(); return v != null ? (MLogEntry) v.get(i) : null; } /** * MLogEntries als Enumeration ermitteln (thread-spezifisch). * @return Enumeration der MLogEntries */ public static synchronized Enumeration getMLogEntriesTS() { Vector v = getThreadEntry(); return v != null ? v.elements() : null; } /** * MLogEntry an Index i entfernen (thread-spezifisch). * @param i der Index */ public static synchronized void removeMLogEntryTS(int i) { Vector v = getThreadEntry(); if (v != null) { v.remove(i); } } /** * MLogEntry entfernen (thread-spezifisch). * @param pMLogEntry ein MLogEntry, der bereits enthalten ist */ public static synchronized void removeMLogEntryTS(MLogEntry pMLogEntry) { Vector v = getThreadEntry(); if (v != null) { v.remove(pMLogEntry); } } //--------------------------------------------------------------------------- /** * Fall (2), siehe checkMagic(String). * @param s auszugebender Text * @param i Index des ":" im Text * @return ggf. manipulierter auszugebender Text */ private static String checkMagic(String s, int i) { String text = s.substring(0, i); // ohne ":" und nachfolgenden Text String add = ""; String key = Thread.currentThread().getName(); Stack stack = (Stack) statThreadStacks.get(key); if (stack != null) { if (stack.size() != 0) { // // Variante 1: // // Nur das oberste Stack-Element pr?fen, falls das passt, Zeit eintragen // und Element entfernen. // /* ThreadStackEntry entry = (ThreadStackEntry) stack.peek(); if (text.equals(entry.getText())) { stack.pop(); if (stack.size() == 0) { statThreadStacks.remove(key); } long time = System.currentTimeMillis() - entry.getTime(); add = time < 1000 ? "" + time + " ms" : time < 1000000 ? "" + ((double) time / 1000) + " s" : "" + (time / 1000) + " s"; } else { add = ""; } */ // // Variante 2: // // Den Stack von oben beginnend nach einem passenden Element // durchsuchen, falls gefunden die Zeit eintragen und dieses Element // und alle dar?ber liegenden entfernen. // int size = stack.size(); int j = size; boolean found = false; while ((j > 0) && !found) { j--; ThreadStackEntry entry = (ThreadStackEntry) stack.get(j); if (text.equals(entry.getText())) { while (size != j) { size--; stack.remove(size); } if (size == 0) { statThreadStacks.remove(key); } long time = System.currentTimeMillis() - entry.getTime(); add = time < 1000 ? "" + time + " ms" : time < 1000000 ? "" + ((double) time / 1000) + " s" : "" + (time / 1000) + " s"; found = true; } } if (!found) { add = ""; } } else { add = ""; } } else { add = ""; } s = s.substring(0, i + 2) + add + s.substring(i + 1); // Space 2x (!) return s; } /** * Pr?fen, ob der auszugebende Text (1) mit 3 Punkten ohne vorangestelltes * Leerzeichen oder (2) auf ": Ok." bzw. ": Error." endet. * Im Fall (1) wird der Text vor den 3 Punkten samt Zeitstempel registriert. * Im Fall (2) wird nach dem Textteil vor dem ":" in den registrierten Texten * gesucht und falls gefunden, die zeitliche Differenz zu dem Eintrag in den * auszugebenden Text eingef?gt, au?erdem wird der Registrierungseintrag (und * ggf. sp?ter hinzugef?gte) wieder entfernt. * @param s auszugebender Text * @return ggf. manipulierter auszugebender Text */ private static String checkMagic(String s) { String res = s; if (s != null) { int len = s.length(); if (s.endsWith("...") && (len > 3) && (s.charAt(len - 4) != ' ')) { // Anfang String text = s.substring(0, len - 3); // ohne die 3 Punkte String key = Thread.currentThread().getName(); Stack stack = (Stack) statThreadStacks.get(key); if (stack == null) { stack = new Stack(); statThreadStacks.put(key, stack); } stack.push(new ThreadStackEntry(text)); // Sicherheitspr?fung, damit der Speicher nicht voll l?uft // (auf Maximalzahl von Eintr?gen pr?fen) if (stack.size() > MAX_THREAD_STACK_SIZE) { stack.remove(0); } // Sicherheitspr?fung ?ber alle Thread-Stack-Eint?ge synchronized (statThreadStacks) { long curtime = System.currentTimeMillis(); if (statLastFullCheck < curtime - 1 * 60 * 1000) { statLastFullCheck = curtime; long time = curtime - 60 * 60 * 1000; Enumeration e = statThreadStacks.keys(); while (e.hasMoreElements()) { String k = (String) e.nextElement(); // if (!key.equals(k)) // { Stack v = (Stack) statThreadStacks.get(key); while ((v.size() != 0) && (((ThreadStackEntry) v.get(0)).getTime() < time)) { ThreadStackEntry tse = (ThreadStackEntry) v.get(0); System.out.println("MLogger: remove entry [ " + tse.getText() + " ]."); // hier explizit n?tig v.remove(0); } if (v.size() == 0) { System.out.println("MLogger: remove stack."); // hier explizit n?tig statThreadStacks.remove(k); } // } } } } } else if (s.endsWith(": Ok.") && (len > 5) && (s.charAt(len - 6) != ' ')) { res = checkMagic(s, len - 5); } else if (s.endsWith(": Error.") && (len > 8) && (s.charAt(len - 9) != ' ')) { res = checkMagic(s, len - 8); } } return res; } /** * Sicherstellen, da? wenigstens ein MLogEntry vorhanden ist. Falls keiner * vorhanden ist, wird ein Standard-MLogEntry (MLogEntry4Text) hinzugef?gt. * * Neu (ab Version 1.24 vom 17.01.2018): Falls die Datei "mlogger.properties" * im Klassenpfad und darin ein Eintrag namens "StdMLogEntry" samt Wert * gefunden wird, dann wird versucht, eine Instanz der angegebenen Klasse * zu erzeugen und auf MLogEntry zu casten. Falls dies gelingt, wird diese * Instanz als Standard-MLogEntry verwendet, andernfalls wie bisher eine * Instanz von MLogEntry4Text. * * @see #statMLogEntries * @see #addMLogEntry(MLogEntry) */ public static synchronized void checkMLogEntries() { if (statMLogEntries.size() == 0) { MLogEntry mle = null; InputStream is = null; try { // zuerst die Property-Datei im aktuellen Verzeichnis suchen try { is = new FileInputStream(PROP_FILENAME); } catch (IOException ex) { // "Can't find " + PROP_FILENAME + "." } // falls nicht gefunden: System-Property mlogger.config.dir pr?fen und falls vorhanden in diesem Verzeichnis suchen if (is == null) { String dir = System.getProperty(SYSTEM_PROPERTY_NAME); if (dir != null) { try { is = new FileInputStream(new File(dir, PROP_FILENAME)); } catch (IOException ex) { // "Can't find " + PROP_FILENAME + "." } } } // falls auch nicht gefunden, dann im Klassenpfad suchen if (is == null) { is = MLogger.class.getResourceAsStream("/" + PROP_FILENAME); } // falls gefunden: verarbeiten, sonst ohne Property-Datei weiter if (is != null) { System.out.println("Found " + PROP_FILENAME + "."); // hier explizit n?tig, da vor MLogger-Initialisierung Properties p = new Properties(); try { p.load(is); } catch (Exception ex) { System.out.println("Error loading properties: " + ex.getMessage()); // hier explizit n?tig, da vor MLogger-Initialisierung ex.printStackTrace(); // hier explizit n?tig, da vor MLogger-Initialisierung } try { String cn = p.getProperty("StdMLogEntry"); if (cn != null) { cn = cn.trim(); if (cn.length() > 0) { Class c = Class.forName(cn); mle = (MLogEntry) c.newInstance(); } } } catch (Exception ex) { System.out.println("Can't create new instance of mlogentry: " + ex.getMessage()); // hier explizit n?tig, da vor MLogger-Initialisierung ex.printStackTrace(); // hier explizit n?tig, da vor MLogger-Initialisierung } if (mle != null) { mle.init(p); } } } finally { if (is != null) { try { is.close(); } catch (IOException ioex) { } } } addMLogEntry(mle != null ? mle : new MLogEntry4Text()); } } /** * Name der Methode ermitteln, die den Logger aufgerufen hat. Dieser * Methodenname wird dann als "Ort" verwendet. * @param idx Index im StackTrace f?r Ermittlung des Methodennamen, * alt: 3, neu: 4 * @return Methodenname incl. Packages (Fehlerfall: null) */ private static String getCallerMethodName(int idx) { Throwable t = new Throwable("X"); StackTraceElement[] stes = t.getStackTrace(); /* for (int i = 0; i < stes.length; i++) { "[" + i + "] = " + stes[i].getClassName() + "." + stes[i].getMethodName() } */ // // Aufbau: // // [0] = "getCallerMethodName(int)" "getCallerMethodName(int)" // [1] = "dispatch(int, BiConsumer)" "checkLevel(int)" // [2] = "print*(int, *)" "checkxxx()" // [3] = eine der MLogger-Methoden // // => Also ist idx mal = 4 (bei normalen Ausgaben) und mal = 3 (bei checkLevel) // // Deutlich besser w?re es aber wohl, das Feld von vorne beginnen zu durchlaufen, // bis keine MLogger-Methode mehr gefunden wurde (au?er vielleicht main(...), damit die Tests dort noch funktionieren). // Au?erdem m?ssten Methoden aus dem SLF4J-SimpleLogger "?berlesen" werden, damit man dessen Aufrufstellen findet. // int i = 0; while (i < stes.length) { StackTraceElement ste = stes[i]; String cni = ste.getClassName(); if (!"com.sta.mlogger.MLogger".equals(cni)) { if (!"org.slf4j.impl.SimpleLogger".equals(cni)) { String mni = ste.getMethodName(); return cni + "." + mni; // break; } } else { String mni = ste.getMethodName(); if ("main".equals(mni)) { return cni + "." + mni; // break; } } i++; } // R?ckfall auf die urspr?ngliche Realisierung String cn = stes[idx].getClassName(); String mn = stes[idx].getMethodName(); /* int i = cn.lastIndexOf('.'); if (i >= 0) { cn = cn.substring(i + 1); } */ return cn + "." + mn; } /** * Verteilung der auszugebenden Nachricht bzw. des Message-Builders an die zust?ndigen MLogEntries. * @param pLevel vorgegebener LogLevel * @param c Consumer mit MLogEntry und Location */ private static void dispatch(int pLevel, BiConsumer c) { String location = null; // // Zuerst Thread-MLogEntries... // Vector v = getThreadEntry(); if (v != null) { int size = v.size(); for (int i = size - 1; i >= 0; i--) { MLogEntry le = (MLogEntry) v.get(i); if (location == null) { location = getCallerMethodName(4); } if (le.checkLevel(location, pLevel)) { // le.println(location, pLevel, pStrg); c.accept(le, location); } if (le.getBreakAfterOutput()) { return; } } } // // ... dann die "normalen" MLogEntries // int size = statMLogEntries.size(); for (int i = size - 1; i >= 0; i--) { MLogEntry le = (MLogEntry) statMLogEntries.get(i); if (location == null) { location = getCallerMethodName(4); } if (le.checkLevel(location, pLevel)) { // le.println(location, pLevel, pStrg); c.accept(le, location); } // "BreakAfterOutput" pr?fen (siehe obere Schleife)? } } /** * Text ausgeben. * Diese Nachricht wird an alle registrierten MLogEntries weitergereicht. * Wichtig ist, dass diese Methode immer von Methoden aus MLogger selbst * aufgerufen wird. Diese (aufrufenden) Methon m?ssen direkt von au?erhalb * aufgrufen worden sein. Auf dieser Basis wird derzeit der Ort (Methodenname) * ermittelt. * @param pLevel vorgegebener LogLevel * @param pStrg der auszugebende Text * @see #checkMLogEntries() */ private static void println(int pLevel, String pStrg) { checkMLogEntries(); String msg = checkMagic(pStrg); dispatch(pLevel, (le, location) -> le.println(location, pLevel, msg)); } /** * Text ausgeben (ohne Zeilenumbruch). * Diese Nachricht wird an alle registrierten MLogEntries weitergereicht. * Wichtig ist, dass diese Methode immer von Methoden aus MLogger selbst * aufgerufen wird. Diese (aufrufenden) Methon m?ssen direkt von au?erhalb * aufgrufen worden sein. Auf dieser Basis wird derzeit der Ort (Methodenname) * ermittelt. * @param pLevel vorgegebener LogLevel * @param pStrg der auszugebende Text * @see #checkMLogEntries() */ private static void print(int pLevel, String pStrg) { checkMLogEntries(); String msg = checkMagic(pStrg); dispatch(pLevel, (le, location) -> le.print(location, pLevel, msg)); } /** * Text bei Bedarf erstellen und unter bestimmtem Level ausgeben. * @param pLevel Level * @param mb Message-Builder */ private static void println(int pLevel, IMessageBuilder mb) { checkMLogEntries(); IMessageBuilder mb2 = mb instanceof MMessageBuilder ? mb : new MMessageBuilder(mb); dispatch(pLevel, (le, location) -> le.println(location, pLevel, mb2)); } /** * Text bei Bedarf erstellen und unter bestimmtem Level ausgeben (ohne Zeilenumbruch). * @param pLevel Level * @param mb Message-Builder */ private static void print(int pLevel, IMessageBuilder mb) { checkMLogEntries(); // doprintln(pLevel, mb instanceof MMessageBuilder ? mb : new MMessageBuilder(mb)); // === Versuch ... === IMessageBuilder mb2 = mb instanceof MMessageBuilder ? mb : new MMessageBuilder(mb); dispatch(pLevel, (le, location) -> le.print(location, pLevel, mb2)); // === ... Versuch === } /** * Pr?fen, ob eine Nachricht mit einem bestimmten Level ausgegeben w?rde. * @param pLevel Level * @return true: Nachricht w?rde ausgegeben */ private static synchronized boolean checkLevel(int pLevel) { String location = null; Enumeration e1 = statMLogEntries.elements(); while (e1.hasMoreElements()) { MLogEntry le = (MLogEntry) e1.nextElement(); if (location == null) { location = getCallerMethodName(3); } if (le.checkLevel(location, pLevel)) { return true; } } Vector v = getThreadEntry(); if (v != null) { Enumeration e2 = v.elements(); while (e2.hasMoreElements()) { MLogEntry le = (MLogEntry) e2.nextElement(); if (location == null) { location = getCallerMethodName(3); } if (le.checkLevel(location, pLevel)) { return true; } } } return false; } //--------------------------------------------------------------------------- /** * StackTrace der Exception (des "Throwable") holen und an pStrg anf?gen, * dabei wird jeweils ein "\n" zwischen den Zeilen eingef?gt (auch nach pStrg). * @param pStrg zuvor stehender Text (kann auch null sein) * @param t die Exception (das "Throwable") * @return pStrg + StackTrace */ public static String convThrowable2String(String pStrg, Throwable t) { if (t != null) { /* ByteArrayOutputStream baos = new ByteArrayOutputStream(); t.printStackTrace(new PrintStream(baos)); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); BufferedReader br = new BufferedReader(new InputStreamReader(bais)); try { String s; while ((s = br.readLine()) != null) { if (pStrg == null) { pStrg = s; } else { pStrg += "\n" + s; } } } catch (IOException e) { } */ StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); String s = sw.toString(); return pStrg + "\n" + s; } return pStrg; } //--------------------------------------------------------------------------- /** * Text als "Error" (Fehler) ausgeben. * Bsp.: *
   * Error (CallerMethodName): This is the given text.
   * 
* @param pStrg der auszugebende Text */ public static void err(String pStrg) { println(MLogEntry.ERROR, pStrg); } /** * Text bei Bedarf erstellen und als "Error" (Fehler) ausgeben. * @param mb Message-Builder */ public static void err(IMessageBuilder mb) { println(MLogEntry.ERROR, mb); } /** * Text und StackTrace der Exception als "Error" (Fehler) ausgeben. * Bsp.: *
   * Error (CallerMethodName): This is the given text.
   * java.lang.NullPointerException
   *     at MyClass.mash(MyClass.java:9)
   *     at MyClass.crunch(MyClass.java:6)
   *     at MyClass.main(MyClass.java:3)
   * 
* @param pStrg der auszugebende Text * @param t a throwable (exception or error), which should be shown */ public static void err(String pStrg, Throwable t) { // StackTrace der Exception holen und an pStrg anf?gen // alt: // pStrg = convThrowable2String(pStrg, t); // println(MLogEntry.ERROR, pStrg); // neu: println(MLogEntry.ERROR, () -> convThrowable2String(pStrg, t)); } /** * Text bei Bedarf erstellen und als "Error" (Fehler) ausgeben. * @param mb Message-Builder * @param t a throwable (exception or error), which should be shown */ public static void err(IMessageBuilder mb, Throwable t) { println(MLogEntry.ERROR, () -> convThrowable2String(mb.getMessage(), t)); } /** * Pr?fen ob Fehler ausgegeben w?rden. * @return true: ja */ public static boolean checkerr() { return checkLevel(MLogEntry.ERROR); } //--------------------------------------------------------------------------- /** * Text als "Warning" (Warnung) ausgeben. * Bsp.: * Warning (CallerMethodName): This is the given text. * @param pStrg der auszugebende Text */ public static void wrn(String pStrg) { println(MLogEntry.WARNING, pStrg); } /** * Text bei Bedarf erstellen und als "Warning" (Warnung) ausgeben. * @param mb Message-Builder */ public static void wrn(IMessageBuilder mb) { println(MLogEntry.WARNING, mb); } /** * Text und StackTrace der Exception als "Warning" (Warnung) ausgeben. * Bsp.: *
   * Error (CallerMethodName): This is the given text.
   * java.lang.NullPointerException
   *     at MyClass.mash(MyClass.java:9)
   *     at MyClass.crunch(MyClass.java:6)
   *     at MyClass.main(MyClass.java:3)
   * 
* @param pStrg der auszugebende Text * @param t a throwable (exception or error), which should be shown */ public static void wrn(String pStrg, Throwable t) { // StackTrace der Exception holen und an pStrg anf?gen // alt: // pStrg = convThrowable2String(pStrg, t); // println(MLogEntry.WARNING, pStrg); // neu: println(MLogEntry.WARNING, () -> convThrowable2String(pStrg, t)); } /** * Text bei Bedarf erstellen und als "Debug" (Debug-Nachricht) ausgeben. * @param mb Message-Builder * @param t a throwable (exception or error), which should be shown */ public static void wrn(IMessageBuilder mb, Throwable t) { println(MLogEntry.WARNING, () -> convThrowable2String(mb.getMessage(), t)); } /** * Pr?fen ob Warnungen ausgegeben w?rden. * @return true: ja */ public static boolean checkwrn() { return checkLevel(MLogEntry.WARNING); } //--------------------------------------------------------------------------- /** * Text als "Info" (wichtige Information) ausgeben. * Bsp.: * Info (CallerMethodName): This is the given text. * @param pStrg der auszugebende Text */ public static void inf(String pStrg) { println(MLogEntry.INFO, pStrg); } /** * Text bei Bedarf erstellen und als "Info" (wichtige Information) ausgeben. * @param mb Message-Builder */ public static void inf(IMessageBuilder mb) { println(MLogEntry.INFO, mb); } /** * Text bei Bedarf erstellen und als "Info" (wichtige Information) ausgeben. * @param pFormat Text bzw. Format-Angaben * @param pObjects Parameter-Objekte (kann auch leer/null sein) */ public static void inf(String pFormat, Object... pObjects) { println(MLogEntry.INFO, new MMessageFormater(pFormat, pObjects)); } /** * Leerzeile als "Info" (wichtige Information) ausgeben. */ public static void inf() { println(MLogEntry.INFO, ""); } /** * Pr?fen ob Infos ausgegeben w?rden. * @return true: ja */ public static boolean checkinf() { return checkLevel(MLogEntry.INFO); } //--------------------------------------------------------------------------- /** * Text als "Message" (allgemeine Nachricht) ausgeben. * Bsp.: * Message (CallerMethodName): This is the given text. * @param pStrg der auszugebende Text */ public static void msg(String pStrg) { println(MLogEntry.MESSAGE, pStrg); } /** * Text bei Bedarf erstellen und als "Message" (allgemeine Nachricht) * ausgeben. * @param mb Message-Builder */ public static void msg(IMessageBuilder mb) { println(MLogEntry.MESSAGE, mb); } /** * Text bei Bedarf erstellen und als "Message" (allgemeine Nachricht) ausgeben. * @param pFormat Text bzw. Format-Angaben * @param pObjects Parameter-Objekte (kann auch leer/null sein) */ public static void msg(String pFormat, Object... pObjects) { println(MLogEntry.MESSAGE, new MMessageFormater(pFormat, pObjects)); } /** * Leerzeile als "Message" (allgemeine Nachricht) ausgeben. */ public static void msg() { println(MLogEntry.MESSAGE, ""); } /** * Pr?fen ob Nachrichten ausgegeben w?rden. * @return true: ja */ public static boolean checkmsg() { return checkLevel(MLogEntry.MESSAGE); } //--------------------------------------------------------------------------- /** * Text als "Debug" (Debug-Nachricht) ausgeben. * Bsp.: * Debug (CallerMethodName): This is the given text. * @param pStrg der auszugebende Text */ public static void deb(String pStrg) { println(MLogEntry.DEBUG, pStrg); } /** * Text bei Bedarf erstellen und als "Debug" (Debug-Nachricht) ausgeben. * @param mb Message-Builder */ public static void deb(IMessageBuilder mb) { println(MLogEntry.DEBUG, mb); } /** * Text bei Bedarf erstellen und als "Debug" (Debug-Nachricht) ausgeben. * @param pFormat Text bzw. Format-Angaben * @param pObjects Parameter-Objekte (kann auch leer/null sein) */ public static void deb(String pFormat, Object... pObjects) { println(MLogEntry.DEBUG, new MMessageFormater(pFormat, pObjects)); } /** * Leerzeile als "Debug" (Debug-Nachricht) ausgeben. */ public static void deb() { println(MLogEntry.DEBUG, ""); } /** * Pr?fen ob Debug-Meldungen ausgegeben w?rden. * @return true: ja */ public static boolean checkdeb() { return checkLevel(MLogEntry.DEBUG); } //--------------------------------------------------------------------------- /** * Text ausgeben. * @param pStrg der auszugebende Text * @see #println() */ public static void println(String pStrg) { println(MLogEntry.ALL, pStrg); } /** * Text bei Bedarf erstellen und ausgeben. * @param mb Message-Builder */ public static void println(IMessageBuilder mb) { println(MLogEntry.ALL, mb); } /** * Text bei Bedarf erstellen und ausgeben. * @param pFormat Text bzw. Format-Angaben * @param pObjects Parameter-Objekte (kann auch leer/null sein) */ public static void println(String pFormat, Object... pObjects) { println(MLogEntry.ALL, new MMessageFormater(pFormat, pObjects)); } /** * Leerzeile ausgeben. * @see #println(String) */ public static void println() { println(MLogEntry.ALL, ""); } /** * Text ausgeben (ohne Zeilenumbruch). * @param pStrg der auszugebende Text * @see #println() */ public static void print(String pStrg) { print(MLogEntry.ALL, pStrg); } /** * Text bei Bedarf erstellen und ausgeben (ohne Zeilenumbruch). * @param mb Message-Builder */ public static void print(IMessageBuilder mb) { print(MLogEntry.ALL, mb); } /** * Text bei Bedarf erstellen und ausgeben (ohne Zeilenumbruch). * @param pFormat Text bzw. Format-Angaben * @param pObjects Parameter-Objekte (kann auch leer/null sein) */ public static void print(String pFormat, Object... pObjects) { print(MLogEntry.ALL, new MMessageFormater(pFormat, pObjects)); } /** * Pr?fen ob Text-Meldungen ausgegeben w?rden. * @return true: ja */ public static boolean checkall() { return checkLevel(MLogEntry.ALL); } //=========================================================================== /** * Ausf?hrung mit einfachem Logging. * @param pFormat Format, z. B. "%msg" * @param pMaxLevel max. Log-Level, z. B. MLogEntry.ALL * @param r Runnable * @param Exception-Typ * @throws E Exception, die ggf. geworfen wird */ public static void runWithSimpleLogging(String pFormat, int pMaxLevel, ThrowingRunnable r) throws E { MLogEntry mle = new MLogEntry4Text(); mle.setMLogFormat(pFormat); mle.setMaxLevel(pMaxLevel); mle.setBreakAfterOutput(true); MLogger.addMLogEntryTS(mle); try { r.run(); } finally { MLogger.removeMLogEntryTS(mle); } } /** * Ausf?hrung mit einfachem Logging (ALL). * @param pFormat Format, z. B. "%msg" * @param r Runnable * @param Exception-Typ * @throws E Exception, die ggf. geworfen wird */ public static void runWithSimpleLogging(String pFormat, ThrowingRunnable r) throws E { runWithSimpleLogging(pFormat, MLogEntry.ALL, r); } /** * Ausf?hrung mit einfachem Logging ("%msg"). * @param r Runnable * @param pMaxLevel max. Log-Level, z. B. MLogEntry.ALL * @param Exception-Typ * @throws E Exception, die ggf. geworfen wird */ public static void runWithSimpleLogging(int pMaxLevel, ThrowingRunnable r) throws E { runWithSimpleLogging("%msg", pMaxLevel, r); } /** * Ausf?hrung mit einfachem Logging ("%msg", ALL). * @param r Runnable * @param Exception-Typ * @throws E Exception, die ggf. geworfen wird */ public static void runWithSimpleLogging(ThrowingRunnable r) throws E { runWithSimpleLogging("%msg", MLogEntry.ALL, r); } //=========================================================================== /** * Testweise warten. * @param ms Dauer in ms */ private static void sleep(long ms) { try { Thread.sleep(ms); } catch (Exception e) { } } /** * Main-Methode zum Test der Logger-Funktionen. * @param args Dummy */ public static void main(String[] args) { // Falls ein Argument angegeben ist, handelt es sich um einen Dateinamen, // f?r den dann ein MLogEntry4File erzeugt wird. if ((args.length == 7) || (args.length == 9)) { MLogEntry4File le = new MLogEntry4File(); le.setBaseDirectory(args[0].equals(".") ? null : args[0]); le.setBaseFileName(args[1].equals(".") ? null : args[1]); le.setDateTimeSeparator(args[2].equals(".") ? null : args[2]); le.setDateTimeFormat(args[3].equals(".") ? null : args[3]); le.setIndexSeparator(args[4].equals(".") ? null : args[4]); le.setIndexFormat(args[5].equals(".") ? null : args[5]); le.setExtension(args[6].equals(".") ? null : args[6]); if (args.length == 9) { le.setMaxFileSize(args[7] == null ? -1 : new Long(args[7]).longValue()); le.setMaxFileCount(args[8] == null ? -1 : new Integer(args[8]).intValue()); } MLogger.addMLogEntryTS(le); } else if ((args.length == 1) && (args[0].equals("-test"))) { MLogger.deb("Start test..."); MLogger.getMLogEntry(0).setMaxLevel(MLogEntry.MESSAGE); Thread t1 = new Thread() { @Override public void run() { MLogEntry4File le = new MLogEntry4File(); MLogger.addMLogEntryTS(le); int i = 0; while (true) { MLogger.deb("This is Thread 1 message " + i); // sleep(1000); i++; } } }; Thread t2 = new Thread() { @Override public void run() { MLogEntry4File le = new MLogEntry4File(); MLogger.addMLogEntryTS(le); int i = 0; while (true) { MLogger.deb("This is Thread 2 message " + i); // sleep(1000); i++; } } }; t1.start(); sleep(500); t2.start(); try { System.in.read(); } catch (Exception e) { } t1.interrupt(); t2.interrupt(); } else if (args.length != 0) { MLogger.err("Invalid syntax."); MLogger.inf("Syntax: mlogger [ -test ] | [ basedir basefn datetimesep datetimefrm indexsep indexfrm ext [ maxfs maxfc ] ]"); MLogger.inf(" basedir = base directory for log files, without ending file separator ('.' = null)"); MLogger.inf(" basefn = base file name for log files, without path and without extension ('.' = null)"); MLogger.inf(" datetimesep = separator for log files between basefn and date/time ('.' = null)"); MLogger.inf(" datetimefrm = format of date and time, if used in log file name ('.' = null)"); MLogger.inf(" indexsep = separator prior index, if index is not 0 ('.' = null)"); MLogger.inf(" indexfrm = number format for index, if index is not 0 ('.' = null)"); MLogger.inf(" (\"0000\" meens 4 digits, \"####\" meens maximum 4 digits)"); MLogger.inf(" ext = extension for log files incl. '.' (only '.' = null)"); MLogger.inf(" maxfs = maximum file size (in bytes)"); MLogger.inf(" maxfc = maximum file count"); MLogger.inf("Examples:"); MLogger.inf(" mlogger d:\\temp\\sta\\sta2sta log _ yyyy-MM-dd-HH-mm _ 0000 .txt"); MLogger.inf(" mlogger d:\\temp\\sta\\sta2sta log _ yyyy-MM-dd-HH-mm _ 0000 .txt 256 3"); return; } MLogger.msg("MLogger Version " + VERSION + " Copyright (c) " + COPYRIGHT + " " + COMPANY); MLogger.msg("ThreadName = " + Thread.currentThread().getName()); MLogger.err("This is an error message (with throwable) from MLogger.", new Exception("Hallo World!")); MLogger.err("This is an error message (without throwable) from MLogger."); MLogger.wrn("This is a warning message from MLogger."); MLogger.inf("This is an information message from MLogger."); MLogger.msg("This is a 'normal' message from MLogger."); MLogger.deb("This is a debug message from MLogger."); MLogger.println("This is a message from MLogger."); MLogger.println(); /* MLogger.println(); MLogger.println("LineTest..."); MLogger.print("Here comes a line input.\nInput>"); try { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = br.readLine(); MLogger.println("Result: " + line); } catch (Exception ex) { MLogger.err("", ex); } MLogger.print("Here comes a character input.\nInput>"); try { int i = System.in.read(); char ch = (char) i; MLogger.println("Result: " + ch); } catch (Exception ex) { MLogger.err("", ex); } MLogger.println("LineTest: Ok."); MLogger.println(); */ } //=========================================================================== /** * Dummy-Constructor. */ protected MLogger() { } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy