View Javadoc

1   /*
2    * Copyright (c) 1998-2005 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  package jgroup.util.log;
19  
20  import java.io.File;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.ObjectOutputStream;
24  
25  import jgroup.util.Network;
26  import jgroup.util.Util;
27  
28  import org.apache.log4j.Logger;
29  
30  /**
31   * The event logger class provides methods used for logging specific events
32   * to a disk file.  It uses a simple memory based buffer, which is flushed
33   * to disk after a given number of log events, or on demand.  Also, it should
34   * flush and close the file on "clean" system exits, using the shutdown hook
35   * mechanism.
36   * 
37   * @author Rune Vestvik
38   * @author Hein Meling
39   * @since Jgroup 3.0
40   */
41  public class Eventlogger
42  {
43  
44    ////////////////////////////////////////////////////////////////////////////////////////////
45    // Logger
46    ////////////////////////////////////////////////////////////////////////////////////////////
47  
48    /** Obtain logger for this class */
49    private static final Logger log = Logger.getLogger(Eventlogger.class);
50  
51  
52    ////////////////////////////////////////////////////////////////////////////////////////////
53    // Constants
54    ////////////////////////////////////////////////////////////////////////////////////////////
55  
56    /** The filename prefix for the event logs */
57    public static final String PREFIX = "eventlog-";
58  
59    /** The number of event objects to store in memory before flushing */
60    private static final int MEM_SIZE = 10000;
61  
62    /** True if the measurement function should be activated. */
63    public static final boolean ENABLED;
64  
65    /** Initialize static variables */
66    static {
67      ENABLED = Boolean.getBoolean("jgroup.log.measurements");
68      if (log.isDebugEnabled()) {
69        log.debug("Measurement logging " + (ENABLED ? "enabled" : "disabled"));
70      }
71    }
72  
73  
74    ////////////////////////////////////////////////////////////////////////////////////////////
75    // Fields
76    ////////////////////////////////////////////////////////////////////////////////////////////
77  
78    /**
79     * Holds true only if no events has yet been logged;
80     * used to determine if a file needs to be created.
81     * If the file is closed, this is reset to true to allow
82     * creation of a new file.
83     */
84    private static boolean firstEvent = true;
85  
86    /** The object output stream to which events (objects) from this JVM should be logged */
87    private static ObjectOutputStream out;
88  
89    /** Index into the log memory array */
90    private static int index = 0;
91  
92    /** The log memory array */
93    private static final Event[] memLog = new Event[MEM_SIZE];
94  
95    /** The shutdown thread */
96    private static Thread shutdownThread;
97  
98    /** The log file currently active */
99    private static String logFile;
100 
101 
102   ////////////////////////////////////////////////////////////////////////////////////////////
103   // Private methods
104   ////////////////////////////////////////////////////////////////////////////////////////////
105 
106   private static void onShutdown()
107   {
108     if (shutdownThread == null) {
109       shutdownThread = new Thread("EventLogger-ShutdownHook") {
110         public void run()
111         {
112           if (log.isDebugEnabled())
113             log.debug("Running EventLogger-ShutdownHook");
114           close();
115         }
116       };
117       Runtime.getRuntime().addShutdownHook(shutdownThread);
118     }
119   }
120 
121   private static void initLog()
122   {
123     // Set to false to avoid creating multiple log files unecessarily
124     firstEvent = false;
125     onShutdown();
126 
127     String logDir = System.getProperty("jgroup.log.dir");
128     int ran = (int) (Math.random() * 99);
129     StringBuilder buf = new StringBuilder(logDir);
130     buf.append(File.separator);
131     buf.append(PREFIX);
132     buf.append(Network.getLocalMachineName());
133     buf.append("-");
134     buf.append(Util.getTimeString());
135     buf.append("-");
136     buf.append(ran);
137     logFile = buf.toString();
138     if (log.isDebugEnabled())
139       log.debug("Creating log file: " + logFile);
140     try {
141       out = new ObjectOutputStream(new FileOutputStream(logFile));
142     } catch (Exception e) {
143       log.warn("Failed to create: " + logFile, e);
144     }
145   }
146 
147 
148   ////////////////////////////////////////////////////////////////////////////////////////////
149   // Public logger methods
150   ////////////////////////////////////////////////////////////////////////////////////////////
151 
152   /**
153    * Log simple event.
154    */
155   public static void logEvent(String description)
156   {
157     logEvent(null, description);
158   }
159 
160   /**
161    * Log event with both type and description.
162    */
163   public static void logEvent(EventType type, String description)
164   {
165     logEvent(new Event(type, description));
166   }
167 
168   /**
169    * Log any event type.
170    */
171   public static void logEvent(Event event)
172   {
173     if (firstEvent)
174       initLog();
175     memLog[index++] = event;
176     if (index == MEM_SIZE) 
177       flushMem();
178   }
179   
180   /**
181    * Log simple event and flush to disk.
182    */
183   public static void logEventFlush(String description)
184   {
185     logEventFlush(null, description);
186   }
187 
188   /**
189    * Log event with both type and description and flush to disk.
190    */
191   public static void logEventFlush(EventType type, String description)
192   {
193     logEventFlush(new Event(type, description));    
194   }
195 
196   /**
197    * Log any event type and flush to disk.
198    */
199   public static void logEventFlush(Event event)
200   {
201     if (firstEvent)
202       initLog();
203     memLog[index++] = event;
204     flushMem();
205   }
206   
207   /**
208    * Log the given event, ignoring system time and group identifier.
209    */
210   public static void logEventNoSysTime(String description)
211   {
212     logEvent(new Event(0, null, description));
213   }
214 
215   public static void flushMem()
216   {
217     if (out == null) {
218       log.warn("Failed to flush memory; file already closed: " + logFile);
219       return;
220     }
221     try {
222       synchronized (Eventlogger.class) {
223         for (int i = 0; i < index; i++) {
224           out.writeObject(memLog[i]);
225         }
226         out.flush();
227       }
228     } catch (IOException e) {
229       log.warn("Failed to flush memory: " + logFile, e);
230     }
231     index = 0;
232     if (log.isDebugEnabled())
233       log.debug("Flushed the log file: " + logFile);
234   }
235 
236   public static void close()
237   {
238     // Ignore duplicate calls
239     if (out == null)
240       return;
241     flushMem();
242     if (log.isDebugEnabled())
243       log.debug("Closing log file: " + logFile);
244     synchronized (Eventlogger.class) {
245       try {
246         out.close();
247       } catch (IOException e) {
248         // Ignore, may fail if the file was already closed from another thread.
249       }
250       out = null;
251       // Ensure that a new file can be created after a file has been closed
252       firstEvent = true;
253     }
254   }
255 
256 } // END EventLogger