Wie kann man in Java beim Auftritt eines Fehlers die Zeit protokollieren?

astare

Grünschnabel
Hallo ,

ich habe in JUnit ein Programm, welches eine Web-Schnittstelle testet. Während des automatischen Tests treten manchmal Fehler auf. Die Zeitpunkte, in den die Fehler auftreten sollen protokolliert werden.

Wenn erstmal ein Fehler auftritt, soll dieser Fehler sofort per E-Mail gesendet werden. Der nächste Fehler soll erst nach 48 Stunden gesendet werden. D.h. Der Abstand zwischen den Fehlern, die per E-Mail gesendet werden, muss 48 h sein.
Dabei die Idee, die in meinem Programm implementiert werden, ist Folgendes:

if(Fehler) {

sende Fehler per Mail;

warte 48 h; ( innerhalb diese 48 h wird das Prog. weiter mit wenigen zeit Abständen immer ausgeführt und die Fehler werden in einem Ordner protokolliert)

und sende den Nächsten;

}

Wie kann ich diese Idee in meinem Programm (in Java) implementieren?

Auf eine zugige Antwort würde ich freuen.

viele Grüße
 
Hallo,

du könntest Date und Fehlermeldung beim Auftreten eines Fehlers in eine ASCII-Datei schreiben.
Bei jedem Schreiben in die ASCII-Datei überprüfst du, ob der erste Fehler in der ASCII-Datei 48 Stunden oder länger her ist und sendest den Inhalt der ACII-Datei ggfl. per Mail.

Gruß
 
Also du verlangst da ganz schön viel.
Ich hab jetzt des ganze mal so überlegt:

Die MainKlass:
Code:
import java.util.Date;


public class Main {
	private static Date Last_Send;
	private static String To_Send = "Fehlerprotokoll:\n";
	private static Logger log = new Logger();
	public static void main(String[] args) {
		
		String Temp[] = log.Lesen("Last_Send.txt");
		if(Temp!=null)
		{
			Last_Send = new Date();
			Last_Send.setTime(Long.parseLong(Temp[0]));
			System.out.println(Last_Send);
		}
		Fehler("a Fehler");
	}
	public static void Fehler(String Fehler)
	{
		java.util.Date aktuell = new java.util.Date();
		
		

		if(Last_Send==null||aktuell.getTime()-Last_Send.getTime()>(45*60*60*1000))
		{
			String Temp[]=log.Lesen("log.txt");
			if(Temp!=null)
			{
				for (int i = 0; i < Temp.length; i++) {
					To_Send = To_Send + "\n" + Temp[i];
				}
			}
			To_Send = To_Send + "\n" + Fehler + aktuell;
			log.schreiben(String.valueOf(aktuell.getTime()), "Last_Send.txt",true);
			E_mail.postMail("anton.junker@manroland.com", "bla", To_Send, "bla@bla");
			log.schreiben(Fehler + " - " + aktuell, "log.txt",true);
		}
		else
		{
			log.schreiben(Fehler + " - " + aktuell, "log.txt",false);
		}
	}
}

Die EmailKlasse hierfür brauchst du allerdings die JavaMail(mail.jar) -> http://java.sun.com/products/javamail/downloads/index.html
entpacken und die mail.jar als externe Jar angeben.

Code:
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;


public class E_mail{
	public static void postMail(
		String Sender,
        String subject,
        String message, String from)
	{
		try {
		
		String SMTP_Server = "Dein Mailserver";
		Properties props = new Properties();
		props.put("mail.smtp.host",SMTP_Server);
		Session session = Session.getDefaultInstance( props );
		Message msg = new MimeMessage( session );
		InternetAddress addressFrom;
		addressFrom = new InternetAddress( from );
		msg.setFrom( addressFrom );
		InternetAddress addressTo = new InternetAddress(Sender);
		msg.setRecipient( Message.RecipientType.TO, addressTo );
		msg.setSubject( subject );
		msg.setContent( message, "text/plain" );
		Transport.send( msg );
		
		} catch (AddressException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}
}

Die Klasse zum erstellen einer Log datei und zum Merken des Datums wann die letzte Mail rausging:
Code:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class Logger{
	
	public void schreiben(String Daten,String Datei,boolean overwrite){

		String b_Daten[] = null;
		if(overwrite==false)
		{
			b_Daten = Lesen(Datei);
		}
		FileWriter fw2;
		
		try 
		{
			fw2 = new FileWriter(Datei);
			if(b_Daten!=null)
			{
				for (int i = 0; i < b_Daten.length; i++) 
				{
					fw2.write(b_Daten[i]);
					fw2.write("\n");
				}
			}
			fw2.write(Daten);
			fw2.write("\n");
			fw2.close();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}	
	}
	public String[] Lesen(String txt){
		try {
			if((new File(txt)).isFile())
			{
			BufferedReader br =
			  new BufferedReader(new FileReader(txt));

			String zeile;
			
				zeile = br.readLine();
			
			ArrayList<String> arrLi_Daten = new ArrayList<String>();
			while (zeile != null) {
				arrLi_Daten.add(zeile);	
				zeile = br.readLine();
			}
			String[] Temp = new String[arrLi_Daten.size()];
			for (int i = 0; i < Temp.length; i++) {
				Temp[i] = arrLi_Daten.get(i);
			}
			return Temp;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
		return null;
	}
}

Ich stehe gerne für Fragen offen^^
Aber sowas in der Art hast du doch gesucht oder?

Grüße
Anton
 
Da hat sich jemand wieder mehr Arbeit gemacht als notwendig. :D
im Paket java.util.logging gibt es schon eine Klasse Logger. Der fügt man noch einen oder mehrere Handler bei, und schon kann man damit Protokollausgaben machen. Ich habe mir mal selber eine Handler-Klasse geschrieben, um Ausgaben in ein JTextArea zu ermöglichen. Ich kann das ja mal demnächst hier veröffentlichen.
 
Würd mich freuen Dank
des mit der Logger Klasse is mir nie aufgefallen. Danke für den Hinweis aber meine Klasse t ja auch und is scho uralt^^

Grüße
Anton
 
Hier ist der Handler für das JTextArea:
Java:
package Logging;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

import javax.swing.JTextArea;


public class LogJTextAreaHandler extends Handler
{
  private HashSet<JTextArea> jtaList;
  
  public LogJTextAreaHandler()
  { super(); jtaList = new LinkedHashSet<JTextArea>(); }
  public LogJTextAreaHandler(JTextArea jta)
  { this(); add(jta); }
  
  public void add(JTextArea t)
  { if ( t == null ) return; jtaList.add(t); }
  public void remove(JTextArea t)
  { if ( t == null ) return; jtaList.remove(t); }

  @Override
  public void close() throws SecurityException
  {
    jtaList.clear();
  }

  @Override
  public void flush()
  {
    // TODO Auto-generated method stub
  }

  private String sev2str(Level l)
  {
    String str = l.toString();
    if ( l == null ) return "";
    else if ( l == Level.INFO ) 
    { str = "Information"; }
    else if ( l == Level.WARNING ) 
    { str = "Warnung"; }
    else if ( l == Level.SEVERE ) 
    { str = "Fehler"; }
    else str = l.toString();
    return str;
  }
  @Override
  public void publish(LogRecord record)
  {
    // TODO Auto-generated method stub
    if ( record == null ) return;
    GregorianCalendar gc = new GregorianCalendar();
    gc.setTimeInMillis(record.getMillis());  
    String str;
    str 
    = String.format("%1$02d.%2$02d.%3$04d %4$02d:%5$02d:%6$02d"
    , gc.get(Calendar.DAY_OF_MONTH) 
    , gc.get(Calendar.MONTH)+1
    , gc.get(Calendar.YEAR)
    , gc.get(Calendar.HOUR_OF_DAY) 
    , gc.get(Calendar.MINUTE)
    , gc.get(Calendar.SECOND));
    str 
    += ""
    + " "
    + sev2str(record.getLevel())
    + ": "
    + record.getMessage()
    + "\n";
    for ( JTextArea jta : jtaList )
    { if (jta==null) continue; jta.append(str); }
  }

}
Und hier ist eine Klasse mit einem Panel für ein JTextArea, das zum Logging verwendet wird:
Java:
package Logging;


import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Handler;
import java.util.logging.Logger;

import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;

public class LogPanel extends JPanel
implements ActionListener
{
  /**
   * 
   */
  private static final long serialVersionUID = 1L;
  private static final String cmdSAVE = "SAVE";
  private static final String cmdCLEAR = "CLEAR";
  private JButton tbbClear;
  private JButton tbbSave;
  private JTextArea txtLog;
  private Logger logger;
  private JScrollPane jsp;

  public LogPanel()
  {
    this.setLayout(new BorderLayout());
    createToolBar();
    txtLog = new JTextArea();
    txtLog.setEditable(false);
    handler = new LogJTextAreaHandler(txtLog);
    jsp = new JScrollPane(txtLog);
    add(jsp,BorderLayout.CENTER);
  }

  private void createToolBar()
  {
    String txt;
    JButton btn;
    
    JToolBar jtb = new JToolBar();
    jtb.setRollover(true);
    
    txt = "Speichern";
    btn = new JButton();
    btn.setText(txt);
    btn.setToolTipText(txt);
    btn.setActionCommand(cmdSAVE);
    btn.addActionListener(this);
    jtb.add(btn);
    tbbSave = btn;
    
    jtb.addSeparator();
    
    txt = "Löschen";
    btn = new JButton();
    btn.setText(txt);
    btn.setToolTipText(txt);
    btn.setActionCommand(cmdCLEAR);
    btn.addActionListener(this);
    jtb.add(btn);
    tbbClear = btn;
    
    add( jtb, BorderLayout.PAGE_START );  
  }

  public void setSaveIcon (Icon icn)
  {
    if ( tbbSave == null ) return;
    tbbSave.setIcon(icn);
  }
  public void setClearIcon (Icon icn)
  {
    if ( tbbClear == null ) return;
    tbbClear.setIcon(icn);
  }
  public void setSaveText (String txt)
  {
    if ( tbbSave == null ) return;
    tbbSave.setText(txt);
  }
  public void setClearText (String txt)
  {
    if ( tbbClear == null ) return;
    tbbClear.setText(txt);
  }
  public void clear()
  { txtLog.setText(""); }
  public void save()
  {
    JFileChooser jfc = new JFileChooser();
    jfc.setMultiSelectionEnabled(false);
    int ret = jfc.showSaveDialog(this);
    if ( ret != JFileChooser.APPROVE_OPTION )
    { return; }
    try
    {
      FileWriter fw = new FileWriter(jfc.getSelectedFile());
      fw.write(txtLog.getText());
      fw.close();
    }
    catch (IOException e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return;
  }
  @Override
  public void actionPerformed(ActionEvent e)
  {
    // TODO Auto-generated method stub
    if ( e == null ) return;
    else if ( e.getActionCommand().equals(cmdCLEAR))
    { clear(); }
    else if ( e.getActionCommand().equals(cmdSAVE))
    { save(); }
  }

  private Handler handler;
  private void listen()
  {
    if ( logger  == null ) return;
    if ( handler == null ) return;
    logger.addHandler(handler);
    return;
  }
  private void unlisten()
  {
    if ( logger  == null ) return;
    if ( handler == null ) return;
    logger.removeHandler(handler);
    return;
  }
  public void setLogger(Logger logger)
  {
    unlisten();
    this.logger = logger;
    listen();
  }

  public Logger getLogger()
  {
    return logger;
  }
  public void finalize()
  {
    unlisten();
    try
    {
      super.finalize();
    }
    catch (Throwable e)
    {
      // TODO Auto-generated catch block
      //e.printStackTrace();
    }
  }
}
Die beiden Klassen sind auch in der angehängten JAR-Datei zu finden.

Und so kann man das Panel bei sich einfügen:
Java:
// nur ein Beispiel ;)
    logger = Logger.getLogger("");
    logPnl = new LogPanel();
    logPnl.setLogger(logger);
    splLog = new JSplitPane();
    splLog.setOrientation(JSplitPane.VERTICAL_SPLIT);
    splLog.setRightComponent(logPnl);
    add(splLog,BorderLayout.CENTER);
Und hier ein Beispiel für die Verwendung des Loggers.
Java:
// So habe ich es bei mir verwendet
// SQLExceptions können miteinander verkettet sein
    catch (SQLException e)
    {
      logPnl.setLogger(logger);
      while ( e != null )
      {
        logger.log(Level.SEVERE, e.getMessage()+" - "+e.getErrorCode());
        e = e.getNextException();
      }
    }
Die Klassen sind ursprünglich nur für den Eigenbedarf gedacht gewesen, darum sind sie auch nicht besonders toll dokumentiert, aber die Arbeitsweise dürfte einigermaßen gut nachvollziehbar sein. Wer sie noch ein wenig verbessert, möge das bitte hier posten.
Weitergabe, Veränderung und Verwendung sind in vollem Umfang von mir gestattet, ich unterstelle es der BSD-Lizenz.
 

Anhänge

Hallo,

log4j - die beliebte third party alternative zu den Sun Klassen - bietet auch einen Logger für email.
Dort nennen sich die entprechenden Komponenten Appender. Deine Spezialanforderungen mit senden alle 48h muss man selbst irgendwie umsetzten. Zumindest das technische Konstrukt zum bequemen loggen über email ist schon mal da.

Eine Konfiguration für logging via email könnte so aussehen:
Code:
<!-- Appender für dieselbe Ausgabe via email -->
  <appender name="mail" class="org.apache.log4j.net.SMTPAppender">
    <param name="SMTPHost" value="smtp.myservername.xx" />
    <param name="From" value="email@fromemail.xx" />
    <param name="To" value="toemail@toemail.xx" />
    <param name="Subject" value="[LOG] ..." />
    <param name="BufferSize" value="1" />
    <param name="threshold" value="error" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern"
        value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n" />
    </layout>
  </appender>

Quelle: http://wiki.apache.org/logging-log4j/SMTPAppender
 
Danke für deine Antwort Anton!

Du hast dir wirklich viel Mühe gemacht!

Die Mail- und Logger-Klasse habe ich schon in meine Klasse implementiert und funktionieren auch!
in test-Methode will ich den erste Fehler senden und die nächsten aber erst nach 48h

private void test(String url) throws XpathException, SAXException, IOException {
// Instanz auf HttpGet bzw. HttpClient kreieren
HttpGet get = new HttpGet(url);
HttpClient client1 = new DefaultHttpClient();
HttpResponse response = client1.execute(get);

//FehlerAuslösen
if(response.getStatusLine().getStatusCode() == 400 ||response.getStatusLine().getStatusCode() == 404){

try {

long time1 = System.currentTimeMillis();
long time2 = lese(time1);

if(time1-time2 >= 48h ){

//sende mail
login(); //funktioniert

....// user daten

logout();//funktioniert
schreibe(t1);

}


} catch (RemoteException e) {
// TODO Auto-generated catch block

}

throw new AssertionFailedError("HTTP-Fehler" +url);
}
hier habe ich beim implementieren von time2, lese(t1) und schreibe(t1) probleme. wie kann ich diese in java programmieren?

Grüße
 
ich versteh grad nich gnaz was du erreichen willst mit
time2 = lese(time1)

Die frage was willst du in time2 speichern? Normalerweise müsstest du ja in time2 die zeit des letzten versendens abspeichern.

Vielleicht schaust du dir noch die funktion von Threads die du schlafen legen kannst und öffnest einen neuen Thread der alle 48 Stunden eine Email versendet und die Logdatei leert. Wäre auch ne Möglichkeit.
Lies mal dazu:
http://www.tutorials.de/forum/java/197327-thread-anhalten-und-wieder-starten.html
 
Zurück