com.sta.mlogger.MLogEntry4File Maven / Gradle / Ivy
package com.sta.mlogger;
import java.io.File;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.Properties;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
/**
* Name: MLogEntry4File
* Description: Logger-Eintrag f?r formatierte Textausgabe in eine Datei.
* Diese Klasse ist von MLogEntry4Text abgeleitet.
*
* Copyright: Copyright (c) 2004, 2005, 2017-2021
* Company: >StA-Soft<
* @author StA
* @version 1.3
*/
public class MLogEntry4File extends MLogEntry4Text
{
/*
Problem bei Einsatz von "PrintWritern" f?r Dateien:
Greifen mehrere Threads parallel mit verschiedenen MLogEntry4File auf eine
Datei zu, werden auch mehrere PrintWriter verwendet. Dies sollte zu Konflikten
f?hren.
L?sung:
Alle "PrintWriter" werden zentral gehalten, ?ber den absoluten Dateinamen als
Schl?ssel kann ein "PrintWriter" ermittelt werden. Es werden die
PrintWriter-Referenzen gez?hlt. Erst wenn keine Referenz mehr existiert, kann
der "PrintWriter" freigegeben werden.
Haken an der Sache:
Beim Umbenennen von Dateien k?nnen Probleme auftreten, wenn ein Thread den
PrintWriter noch ben?tigt.
Andere Idee:
Beim Hinzuf?gen eines MLogEntry4File wird gepr?ft, ob es bereits einen solchen
f?r genau die Kombination von Parametern (Basisverzeichnis, ... MaxFileCount)
gibt. Falls ja wird dieser ein weiteres Mal f?r einen anderen Thread
registriert. Beim Entfernen wird nur der Verweis bzgl. des betreffenden
Threads entfernt, die Verweise f?r alle anderen Threads bleiben unber?hrt.
Vorteil: Das funktioniert, wenn der MLogEntry4File nicht nachtr?glich
ver?ndert wird. Alle Threads schreiben ?ber den gleichen PrintWriter in eine
Datei. Durch "synchronized" werden die Threads voneinander "abgeschottet".
Nachteil: Eine nachtr?gliche Ver?nderung des MLogEntry4File im "ersten" Thread
wirkt sich auf alle anderen Threads aus, ?nderungen durch andere Threads
werden nicht ber?cksichtigt.
... Realisierung ist sehr umst?ndlich und der Nutzen fragw?rdig, da das
Problem nach dem einf?gen von "synchronized" in den MLogger-public-Methoden
nicht mehr aufgetreten ist. Daher soll vorerst auf eine Umsetzung verzichtet
werden.
*/
//===========================================================================
/**
* Basisverzeichnis f?r Log-Dateien, falls null: nicht verwendet (=aktuelles
* Verzeichnis).
*/
private String myBaseDirectory = null;
/**
* Basisdateiname f?r Log-Dateien, falls null: nicht verwendet.
*/
private String myBaseFileName = "log";
/**
* Separator f?r Log-Dateinamen zwischen Basis-Dateiname und Datum/Uhrzeit,
* falls null: nicht verwendet, nur falls Format f?r Datum/Uhrzeit angegeben.
*/
private String myDateTimeSeparator = "_";
/**
* Java-DateTime-Format von Datum und Uhrzeit im Log-Dateinamen, falls null:
* nicht verwendet.
*/
private String myDateTimeFormat; // = "yyyy-MM-dd"; // "yyyy-MM-dd-HH-mm-ss";
/**
* Format-Objekt f?r Datum und Uhrzeit, falls verwendet.
*/
private SimpleDateFormat sdf;
/**
* Separator f?r Log-Dateinamen zwischen Datum/Uhrzeit und Index, falls null:
* nicht verwendet, nur falls Index-Format angegeben und Index nicht 0.
*/
private String myIndexSeparator = "_";
/**
* Java-Number-Format f?r Index-Angabe in Log-Dateinamen, falls null: nicht
* verwendet, nur falls Index nicht 0.
*/
private String myIndexFormat; // = "000";
/**
* Format-Objekt f?r Index, falls verwendet.
*/
private DecimalFormat df;
/**
* Erweiterung (Extension) f?r Log-Dateinamen, falls null: nicht verwendet.
*/
private String myExtension = ".log";
/**
* Dateigr??e in Bytes, ab der eine Log-Datei abgeschnitten werden soll,
* dabei wird immer eine ganze Zeile geschrieben, sodass die Datei
* theoretisch etwas l?nger als die angegebene Gr??e werden kann.
* Falls -1: nicht verwendet, also Gr??e beliebig.
* Falls gr??er als 0: auch maximale Dateianzahl angeben!
*/
private long myMaxFileSize = -1;
/**
* Maximale Anzahl von Log-Dateien. Es gibt dann die aktuelle Log-Datei und
* n-1 "Backup"-Dateien, wird in Verbindung mit maximaler Gr??e verwendet.
*/
private int myMaxFileCount = -1;
/**
* Name der aktuellen Log-Datei.
*/
private String myCurFileName = null;
//===========================================================================
/**
* Initialisierung eines MLogEntry4File.
* @param pMinLevel minimaler LogLevel
* @param pMaxLevel maximaler LogLevel
* @see #MLogEntry4File(int)
* @see #MLogEntry4File()
*/
public MLogEntry4File(int pMinLevel, int pMaxLevel)
{
super(pMinLevel, pMaxLevel, null);
initDailyRolling();
}
/**
* Initialisierung eines MLogEntry4File mit MinLevel = ERROR.
* @param pMaxLevel maximaler LogLevel
* @see #MLogEntry4File(int, int)
* @see #MLogEntry4File()
*/
public MLogEntry4File(int pMaxLevel)
{
super(pMaxLevel, null);
initDailyRolling();
}
/**
* Initialisierung eines MLogEntry4File mit MinLevel = ERROR und
* MaxLevel = ALL.
* @see #MLogEntry4File(int, int)
* @see #MLogEntry4File(int)
*/
public MLogEntry4File()
{
super(null);
initDailyRolling();
}
//===========================================================================
@Override
public Object clone() throws CloneNotSupportedException
{
MLogEntry4File mle = (MLogEntry4File) super.clone();
String basefilename = mle.getBaseFileName();
String threadname = Thread.currentThread().getName();
mle.setBaseFileName((basefilename != null ? basefilename + "_" : "") + (threadname != null ? threadname.replace(" ", "_") : "" + (int) (Math.random() * 1000000.0)));
return mle;
}
//===========================================================================
/**
* Basisverzeichnis vorgeben.
* @param pBaseDirectory Basisverzeichnis
*/
public void setBaseDirectory(String pBaseDirectory)
{
myBaseDirectory = pBaseDirectory;
}
/**
* Basisverzeichnis ermitteln.
* @return Basisverzeichnis
*/
public String getBaseDirectory()
{
return myBaseDirectory;
}
/**
* Basisdateiname vorgeben.
* @param pBaseFileName Basisdateiname
*/
public void setBaseFileName(String pBaseFileName)
{
myBaseFileName = pBaseFileName;
}
/**
* Basisdateiname ermitteln.
* @return Basisdateiname
*/
public String getBaseFileName()
{
return myBaseFileName;
}
/**
* Separator zwischen Basisdateiname und Datum/Uhrzeit vorgeben.
* @param pDateTimeSeparator der Separator
*/
public void setDateTimeSeparator(String pDateTimeSeparator)
{
myDateTimeSeparator = pDateTimeSeparator;
}
/**
* Separator zwischen Basisdateiname und Datum/Uhrzeit.
* @return der Separator
*/
public String getDateTimeSeparator()
{
return myDateTimeSeparator;
}
/**
* Format von Datum/Uhrzeit vorgeben.
* @param pDateTimeFormat Format von Datum/Uhrzeit
*/
public void setDateTimeFormat(String pDateTimeFormat)
{
myDateTimeFormat = pDateTimeFormat;
sdf = new SimpleDateFormat(myDateTimeFormat);
}
/**
* Format von Datum/Uhrzeit ermitteln.
* @return Format von Datum/Uhrzeit
*/
public String getDateTimeFormat()
{
return myDateTimeFormat;
}
/**
* Separator vor Index vorgeben.
* @param pIndexSeparator der Separator
*/
public void setIndexSeparator(String pIndexSeparator)
{
myIndexSeparator = pIndexSeparator;
}
/**
* Separator vor Index ermitteln.
* @return der Separator
*/
public String getIndexSeparator()
{
return myIndexSeparator;
}
/**
* Format der Indexangabe vorgeben.
* @param pIndexFormat Format der Indexangabe
*/
public void setIndexFormat(String pIndexFormat)
{
myIndexFormat = pIndexFormat;
df = new DecimalFormat(myIndexFormat);
}
/**
* Format der Indexangabe ermitteln.
* @return Format der Indexangabe
*/
public String getIndexFormat()
{
return myIndexFormat;
}
/**
* Extension f?r Log-Datei vorgeben, incl. ".".
* @param pExtension Extension f?r Log-Datei
*/
public void setExtension(String pExtension)
{
myExtension = pExtension;
}
/**
* Extension f?r Log-Datei ermitteln, incl. ".".
* @return Extension f?r Log-Datei
*/
public String getExtension()
{
return myExtension;
}
/**
* Maximale Dateigr??e vorgeben.
* @param pMaxFileSize Maximale Dateigr??e
*/
public void setMaxFileSize(long pMaxFileSize)
{
myMaxFileSize = pMaxFileSize;
}
/**
* Maximale Dateigr??e ermitteln.
* @return Maximale Dateigr??e
*/
public long getMaxFileSize()
{
return myMaxFileSize;
}
/**
* Maximale Dateianzahl vorgeben.
* @param pMaxFileCount Maximale Dateianzahl
*/
public void setMaxFileCount(int pMaxFileCount)
{
myMaxFileCount = pMaxFileCount;
}
/**
* Maximale Dateianzahl ermitteln.
* @return Maximale Dateianzahl
*/
public int getMaxFileCount()
{
return myMaxFileCount;
}
/**
* Initialisierung f?r t?gliches Roll-Over, es wird also eine Log-Datei pro
* Tag erzeugt, eine Dateigr??enbegrenzung wird nicht vorgegeben.
* Die Log-Dateien stehen im aktuellen Verzeichnis und hei?en
* "log_yyyy-MM-dd.log" bzw. "log_yyyy-MM-dd_iiii.log", wobei gilt: yyyy =
* Jahr, MM = Monat, dd = Tag, iiii = Index (falls nicht 0).
*/
public void initDailyRolling()
{
setBaseDirectory(null);
setBaseFileName("log");
setDateTimeSeparator("_");
setDateTimeFormat("yyyy-MM-dd");
setIndexSeparator("_");
setIndexFormat("0000");
setExtension(".log");
setMaxFileSize(-1);
setMaxFileCount(-1);
}
/**
* Initialisierung f?r Roll-Over bei ?berschreiten einer bestimmten
* Dateigr??e, es werden entsprechend der angegebenen Anzahl "Backup"-Dateien
* erzeugt.
* Die Log-Dateien stehen im aktuellen Verzeichnis und hei?en
* "log.log" bzw. "log_iiii.log", wobei gilt: iiii = Index (falls nicht 0).
* @param pMaxFileSize Grenze f?r Dateigr??e
* @param pMaxFileCount Maximale Dateianzahl
*/
public void initSizeCountRolling(long pMaxFileSize, int pMaxFileCount)
{
setBaseDirectory(null);
setBaseFileName("log");
setDateTimeSeparator(null);
setDateTimeFormat(null);
setIndexSeparator("_");
setIndexFormat("0000");
setExtension(".log");
setMaxFileSize(pMaxFileSize);
setMaxFileCount(pMaxFileCount);
}
@Override
public void init(Properties p)
{
super.init(p);
String basedirectory = p.getProperty("BaseDirectory");
if (basedirectory != null)
{
setBaseDirectory(basedirectory);
}
String basefilename = p.getProperty("BaseFileName");
if (basefilename != null)
{
setBaseFileName(basefilename);
}
String datetimeseparator = p.getProperty("DateTimeSeparator");
if (datetimeseparator != null)
{
setDateTimeSeparator(datetimeseparator);
}
String datetimeformat = p.getProperty("DateTimeFormat");
if (datetimeformat != null)
{
setDateTimeFormat(datetimeformat);
}
String indexseparator = p.getProperty("IndexSeparator");
if (indexseparator != null)
{
setIndexSeparator(indexseparator);
}
String indexformat = p.getProperty("IndexFormat");
if (indexformat != null)
{
setIndexFormat(indexformat);
}
String extension = p.getProperty("Extension");
if (extension != null)
{
setExtension(extension);
}
String maxfilesize = p.getProperty("MaxFileSize");
if (maxfilesize != null)
{
setMaxFileSize(Integer.parseInt(maxfilesize));
}
String maxfilecount = p.getProperty("MaxFileCount");
if (maxfilecount != null)
{
setMaxFileCount(Integer.parseInt(maxfilecount));
}
}
//---------------------------------------------------------------------------
/* *
* Standard-Equals-Methode.
* @param other Objekt, mit dem das aktuelle vergleichen werden soll
* @return true falls "logisch gleich"
*/
/*
public boolean equals(Object other)
{
// Standard-Implementation
if (this == other)
{
return true;
}
if (!super.equals(other))
{
return false;
}
// Spezifische Implementation
MLogEntry4File le = (MLogEntry4File) other;
return eqString(myBaseDirectory, le.getBaseDirectory()) &&
eqString(myBaseFileName, le.getBaseFileName()) &&
eqString(myDateTimeSeparator, le.getDateTimeSeparator()) &&
eqString(myDateTimeFormat, le.getDateTimeFormat()) &&
eqString(myIndexSeparator, le.getIndexSeparator()) &&
eqString(myIndexFormat, le.getIndexFormat()) &&
eqString(myExtension, le.getExtension()) &&
(myMaxFileSize == le.getMaxFileSize()) &&
(myMaxFileCount == le.getMaxFileCount());
}
*/
//---------------------------------------------------------------------------
/**
* Dateinamen f?r Index i berechnen.
* @param i Index
* @param now aktuelles Datum und aktuelle Uhrzeit
* @return Dateiname
*/
private String calcFileName(int i, Date now)
{
StringBuilder sb = new StringBuilder();
if (myBaseDirectory != null)
{
sb.append(myBaseDirectory);
if (!myBaseDirectory.endsWith(File.separator))
{
sb.append(File.separator);
}
}
if (myBaseFileName != null)
{
sb.append(myBaseFileName);
}
if (myDateTimeFormat != null)
{
if (myDateTimeSeparator != null)
{
sb.append(myDateTimeSeparator);
}
// SimpleDateFormat sdf = new SimpleDateFormat(myDateTimeFormat);
sb.append(sdf.format(new Date()));
}
if ((myIndexFormat != null) && (i != 0))
{
if (myIndexSeparator != null)
{
sb.append(myIndexSeparator);
}
// DecimalFormat df = new DecimalFormat("0000");
sb.append(df.format(i));
}
if (myExtension != null)
{
sb.append(myExtension);
}
return sb.toString();
}
/**
* Dateiname pr?fen, Datei vorbereiten, Dateien umbenennen, Datei l?schen - alles je nach Bedarf.
*/
protected void checkFileName()
{
Date now = new Date();
String fn = calcFileName(0, now);
// Pr?fen, ob die Dateigr??e bereits ?ber MaxSize liegt.
// Falls ja: L?schen der (MaxFileCount-1)ten Log-Datei, umbenennen aller
// anderen Log-Dateien und setzen des aktuellen Dateinamens auf null
if (myMaxFileSize > 0)
{
long size = -1;
try
{
FileInputStream is = new FileInputStream(fn);
try
{
try
{
size = is.available();
}
catch (IOException e)
{
}
}
finally
{
try
{
is.close();
}
catch (IOException e)
{
}
}
}
catch (FileNotFoundException e)
{
}
if (size >= myMaxFileSize)
{
String fni = calcFileName(myMaxFileCount - 1, now);
new File(fni).delete();
boolean b = true;
PrintWriter pw = getPrintWriter();
if (pw != null)
{
pw.close();
pw = null;
setPrintWriter(null);
myCurFileName = null;
}
for (int i = myMaxFileCount - 1; i > 0; i--)
{
String fnj = calcFileName(i - 1, now);
b = new File(fnj).renameTo(new File(fni));
fni = fnj;
}
// als besonderes Feature: L?schen aller zus?tzlichen Log-Files
// (die entstehen z. B., wenn die max. Anzahl verringert wurde)
// (am besten alle, aber nur einmalig)
/*
int i = myMaxFileCount;
b = true;
while (b)
{
fni = calcFileName(i);
File f = new File(fni);
b = f.exists() && f.delete();
i++;
}
*/
}
}
// Pr?fen, ob sich der Dateiname durch das Datum ?ndern w?rde.
// Falls ja: Alte Datei schlie?en, neue Datei erstellen und PrintWriter
// vorgeben
if ((myCurFileName == null) || (!myCurFileName.equals(fn)))
{
PrintWriter pw = getPrintWriter();
if (pw != null)
{
pw.close();
}
try
{
pw = new PrintWriter(new FileOutputStream(fn, true));
}
catch (FileNotFoundException e)
{
return;
}
setPrintWriter(pw);
// neu:
myCurFileName = fn;
}
}
@Override
protected void println(String pStrg)
{
checkFileName();
// Eigentlichen Text ?ber PrintWriter ausgeben, incl. Flush
super.println(pStrg);
}
@Override
protected void print(String pStrg)
{
checkFileName();
// Eigentlichen Text ?ber PrintWriter ausgeben, incl. Flush
super.print(pStrg);
}
}