EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.message]

COVERAGE SUMMARY FOR SOURCE FILE [TraceSystem.java]

nameclass, %method, %block, %line, %
TraceSystem.java100% (1/1)94%  (17/18)79%  (347/442)80%  (96/120)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TraceSystem100% (1/1)94%  (17/18)79%  (347/442)80%  (96/120)
logWritingError (Exception): void 0%   (0/1)0%   (0/33)0%   (0/8)
setLevelFile (int): void 100% (1/1)31%  (23/74)47%  (9/19)
openWriter (): boolean 100% (1/1)85%  (35/41)73%  (8/11)
closeWriter (): void 100% (1/1)96%  (23/24)90%  (9/10)
writeFile (String, Throwable): void 100% (1/1)96%  (92/96)92%  (24/26)
TraceSystem (String): void 100% (1/1)100% (23/23)100% (9/9)
close (): void 100% (1/1)100% (6/6)100% (3/3)
format (String, String): String 100% (1/1)100% (26/26)100% (3/3)
getLevelFile (): int 100% (1/1)100% (3/3)100% (1/1)
getTrace (String): Trace 100% (1/1)100% (41/41)100% (9/9)
isEnabled (int): boolean 100% (1/1)100% (8/8)100% (1/1)
setFileName (String): void 100% (1/1)100% (4/4)100% (2/2)
setLevelSystemOut (int): void 100% (1/1)100% (6/6)100% (3/3)
setMaxFileSize (int): void 100% (1/1)100% (4/4)100% (2/2)
setName (String): void 100% (1/1)100% (1/1)100% (1/1)
setSysOut (PrintStream): void 100% (1/1)100% (4/4)100% (2/2)
updateLevel (): void 100% (1/1)100% (8/8)100% (2/2)
write (int, String, String, Throwable): void 100% (1/1)100% (40/40)100% (8/8)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.message;
7 
8import java.io.IOException;
9import java.io.PrintStream;
10import java.io.PrintWriter;
11import java.io.Writer;
12import java.text.SimpleDateFormat;
13import java.util.HashMap;
14 
15import org.h2.api.ErrorCode;
16import org.h2.engine.Constants;
17import org.h2.jdbc.JdbcSQLException;
18import org.h2.store.fs.FileUtils;
19import org.h2.util.IOUtils;
20import org.h2.util.New;
21 
22/**
23 * The trace mechanism is the logging facility of this database. There is
24 * usually one trace system per database. It is called 'trace' because the term
25 * 'log' is already used in the database domain and means 'transaction log'. It
26 * is possible to write after close was called, but that means for each write
27 * the file will be opened and closed again (which is slower).
28 */
29public class TraceSystem implements TraceWriter {
30 
31    /**
32     * The parent trace level should be used.
33     */
34    public static final int PARENT = -1;
35 
36    /**
37     * This trace level means nothing should be written.
38     */
39    public static final int OFF = 0;
40 
41    /**
42     * This trace level means only errors should be written.
43     */
44    public static final int ERROR = 1;
45 
46    /**
47     * This trace level means errors and informational messages should be
48     * written.
49     */
50    public static final int INFO = 2;
51 
52    /**
53     * This trace level means all type of messages should be written.
54     */
55    public static final int DEBUG = 3;
56 
57    /**
58     * This trace level means all type of messages should be written, but
59     * instead of using the trace file the messages should be written to SLF4J.
60     */
61    public static final int ADAPTER = 4;
62 
63    /**
64     * The default level for system out trace messages.
65     */
66    public static final int DEFAULT_TRACE_LEVEL_SYSTEM_OUT = OFF;
67 
68    /**
69     * The default level for file trace messages.
70     */
71    public static final int DEFAULT_TRACE_LEVEL_FILE = ERROR;
72 
73    /**
74     * The default maximum trace file size. It is currently 64 MB. Additionally,
75     * there could be a .old file of the same size.
76     */
77    private static final int DEFAULT_MAX_FILE_SIZE = 64 * 1024 * 1024;
78 
79    private static final int CHECK_SIZE_EACH_WRITES = 4096;
80 
81    private int levelSystemOut = DEFAULT_TRACE_LEVEL_SYSTEM_OUT;
82    private int levelFile = DEFAULT_TRACE_LEVEL_FILE;
83    private int levelMax;
84    private int maxFileSize = DEFAULT_MAX_FILE_SIZE;
85    private String fileName;
86    private HashMap<String, Trace> traces;
87    private SimpleDateFormat dateFormat;
88    private Writer fileWriter;
89    private PrintWriter printWriter;
90    private int checkSize;
91    private boolean closed;
92    private boolean writingErrorLogged;
93    private TraceWriter writer = this;
94    private PrintStream sysOut = System.out;
95 
96    /**
97     * Create a new trace system object.
98     *
99     * @param fileName the file name
100     */
101    public TraceSystem(String fileName) {
102        this.fileName = fileName;
103        updateLevel();
104    }
105 
106    private void updateLevel() {
107        levelMax = Math.max(levelSystemOut, levelFile);
108    }
109 
110    /**
111     * Set the print stream to use instead of System.out.
112     *
113     * @param out the new print stream
114     */
115    public void setSysOut(PrintStream out) {
116        this.sysOut = out;
117    }
118 
119    /**
120     * Get or create a trace object for this module. Trace modules with names
121     * such as "JDBC[1]" are not cached (modules where the name ends with "]").
122     * All others are cached.
123     *
124     * @param module the module name
125     * @return the trace object
126     */
127    public synchronized Trace getTrace(String module) {
128        if (module.endsWith("]")) {
129            return new Trace(writer, module);
130        }
131        if (traces == null) {
132            traces = New.hashMap(16);
133        }
134        Trace t = traces.get(module);
135        if (t == null) {
136            t = new Trace(writer, module);
137            traces.put(module, t);
138        }
139        return t;
140    }
141 
142    @Override
143    public boolean isEnabled(int level) {
144        return level <= this.levelMax;
145    }
146 
147    /**
148     * Set the trace file name.
149     *
150     * @param name the file name
151     */
152    public void setFileName(String name) {
153        this.fileName = name;
154    }
155 
156    /**
157     * Set the maximum trace file size in bytes.
158     *
159     * @param max the maximum size
160     */
161    public void setMaxFileSize(int max) {
162        this.maxFileSize = max;
163    }
164 
165    /**
166     * Set the trace level to use for System.out
167     *
168     * @param level the new level
169     */
170    public void setLevelSystemOut(int level) {
171        levelSystemOut = level;
172        updateLevel();
173    }
174 
175    /**
176     * Set the file trace level.
177     *
178     * @param level the new level
179     */
180    public void setLevelFile(int level) {
181        if (level == ADAPTER) {
182            String adapterClass = "org.h2.message.TraceWriterAdapter";
183            try {
184                writer = (TraceWriter) Class.forName(adapterClass).newInstance();
185            } catch (Throwable e) {
186                e = DbException.get(ErrorCode.CLASS_NOT_FOUND_1, e, adapterClass);
187                write(ERROR, Trace.DATABASE, adapterClass, e);
188                return;
189            }
190            String name = fileName;
191            if (name != null) {
192                if (name.endsWith(Constants.SUFFIX_TRACE_FILE)) {
193                    name = name.substring(0, name.length() - Constants.SUFFIX_TRACE_FILE.length());
194                }
195                int idx = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\'));
196                if (idx >= 0) {
197                    name = name.substring(idx + 1);
198                }
199                writer.setName(name);
200            }
201        }
202        levelFile = level;
203        updateLevel();
204    }
205 
206    public int getLevelFile() {
207        return levelFile;
208    }
209 
210    private synchronized String format(String module, String s) {
211        if (dateFormat == null) {
212            dateFormat = new SimpleDateFormat("MM-dd HH:mm:ss ");
213        }
214        return dateFormat.format(System.currentTimeMillis()) + module + ": " + s;
215    }
216 
217    @Override
218    public void write(int level, String module, String s, Throwable t) {
219        if (level <= levelSystemOut || level > this.levelMax) {
220            // level <= levelSystemOut: the system out level is set higher
221            // level > this.level: the level for this module is set higher
222            sysOut.println(format(module, s));
223            if (t != null && levelSystemOut == DEBUG) {
224                t.printStackTrace(sysOut);
225            }
226        }
227        if (fileName != null) {
228            if (level <= levelFile) {
229                writeFile(format(module, s), t);
230            }
231        }
232    }
233 
234    private synchronized void writeFile(String s, Throwable t) {
235        try {
236            if (checkSize++ >= CHECK_SIZE_EACH_WRITES) {
237                checkSize = 0;
238                closeWriter();
239                if (maxFileSize > 0 && FileUtils.size(fileName) > maxFileSize) {
240                    String old = fileName + ".old";
241                    FileUtils.delete(old);
242                    FileUtils.move(fileName, old);
243                }
244            }
245            if (!openWriter()) {
246                return;
247            }
248            printWriter.println(s);
249            if (t != null) {
250                if (levelFile == ERROR && t instanceof JdbcSQLException) {
251                    JdbcSQLException se = (JdbcSQLException) t;
252                    int code = se.getErrorCode();
253                    if (ErrorCode.isCommon(code)) {
254                        printWriter.println(t.toString());
255                    } else {
256                        t.printStackTrace(printWriter);
257                    }
258                } else {
259                    t.printStackTrace(printWriter);
260                }
261            }
262            printWriter.flush();
263            if (closed) {
264                closeWriter();
265            }
266        } catch (Exception e) {
267            logWritingError(e);
268        }
269    }
270 
271    private void logWritingError(Exception e) {
272        if (writingErrorLogged) {
273            return;
274        }
275        writingErrorLogged = true;
276        Exception se = DbException.get(
277                ErrorCode.TRACE_FILE_ERROR_2, e, fileName, e.toString());
278        // print this error only once
279        fileName = null;
280        sysOut.println(se);
281        se.printStackTrace();
282    }
283 
284    private boolean openWriter() {
285        if (printWriter == null) {
286            try {
287                FileUtils.createDirectories(FileUtils.getParent(fileName));
288                if (FileUtils.exists(fileName) && !FileUtils.canWrite(fileName)) {
289                    // read only database: don't log error if the trace file
290                    // can't be opened
291                    return false;
292                }
293                fileWriter = IOUtils.getBufferedWriter(
294                        FileUtils.newOutputStream(fileName, true));
295                printWriter = new PrintWriter(fileWriter, true);
296            } catch (Exception e) {
297                logWritingError(e);
298                return false;
299            }
300        }
301        return true;
302    }
303 
304    private synchronized void closeWriter() {
305        if (printWriter != null) {
306            printWriter.flush();
307            printWriter.close();
308            printWriter = null;
309        }
310        if (fileWriter != null) {
311            try {
312                fileWriter.close();
313            } catch (IOException e) {
314                // ignore
315            }
316            fileWriter = null;
317        }
318    }
319 
320    /**
321     * Close the writers, and the files if required. It is still possible to
322     * write after closing, however after each write the file is closed again
323     * (slowing down tracing).
324     */
325    public void close() {
326        closeWriter();
327        closed = true;
328    }
329 
330    @Override
331    public void setName(String name) {
332        // nothing to do (the file name is already set)
333    }
334 
335}

[all classes][org.h2.message]
EMMA 2.0.5312 (C) Vladimir Roubtsov