001: package Shared.Logging.Internal;
002:
003: import java.io.*;
004: import java.nio.channels.FileChannel;
005: import java.nio.channels.FileLock;
006:
007: /**
008: * The file logger, which writes to a set of files.
009: * If the current target file exceeds a limit size,
010: * the logger changes to the next file.
011: */
012: public class FileLogger extends GenericLogger {
013:
014: private static final String FsDelimiter = System
015: .getProperty("file.separator");
016:
017: private String basisTargetFileName;
018: private String targetFileEnding;
019: private String basisTargetDirectoryPath;
020: private int numberOfTargetFiles;
021: private long fileSizeLimitInBytes;
022:
023: private File[] logFiles;
024:
025: private FileLoggerStream loggerStream;
026:
027: /**
028: * Constructor.
029: * Creates a file logger, which writes to files with
030: * filenames of the form basisTargetFileName_Number.targetFileEnding.
031: * where number is increased when the current file has
032: * exceeded the fileSizeLimitInKiloBytes.
033: * Number will be in the intervall [0..numberOfTargetFiles-1].
034: * basisTargetDirectory must point to a directory with write access.
035: *
036: * The file with index 0 always has the most uptodate log outputs,
037: * and the higher the indes, the older the information contained.
038: *
039: */
040: public FileLogger(String logIdentifier,
041: String _basisTargetFileName, String _targetFileEnding,
042: String _basisTargetDirectoryPath, int _numberOfTargetFiles,
043: int _fileSizeLimitInBytes) throws IOException {
044: super (logIdentifier);
045: this .basisTargetFileName = _basisTargetFileName;
046: this .targetFileEnding = _targetFileEnding;
047: this .basisTargetDirectoryPath = _basisTargetDirectoryPath;
048: this .numberOfTargetFiles = _numberOfTargetFiles;
049: this .fileSizeLimitInBytes = _fileSizeLimitInBytes;
050:
051: // Check all arguments and replace them with default values,
052: // if they are not correctly formulated (roughly..) :
053:
054: // basisTargetFileName:
055: if (this .basisTargetFileName == null) {
056: this .basisTargetFileName = "log";
057: }
058: if (this .basisTargetFileName.trim().length() < 1) {
059: this .basisTargetFileName = "log";
060: }
061: //
062: if (this .basisTargetDirectoryPath == null) {
063: this .basisTargetDirectoryPath = System
064: .getProperty("user.dir");
065: }
066: if (this .basisTargetDirectoryPath.trim().length() < 1) {
067: this .basisTargetDirectoryPath = System
068: .getProperty("user.dir");
069: }
070: // If the basisTargetDirectoryPath ends with a slash or file delimiter,
071: // remove it:
072: if (this .basisTargetDirectoryPath.endsWith("/")
073: || this .basisTargetDirectoryPath.endsWith(FsDelimiter)) {
074: this .basisTargetDirectoryPath = this .basisTargetDirectoryPath
075: .substring(0, this .basisTargetDirectoryPath
076: .length() - 1);
077: }
078: if (this .targetFileEnding == null) {
079: this .targetFileEnding = "log";
080: }
081: if (this .targetFileEnding.trim().length() < 1) {
082: this .targetFileEnding = "log";
083: }
084:
085: // Check the numberOfTargetFiles value:
086: if (this .numberOfTargetFiles < 1) {
087: this .numberOfTargetFiles = 1;
088: System.out
089: .println("FileLogger: Number of logfiles was set to 1, which is the minimum.");
090: }
091: if (this .numberOfTargetFiles > 100) {
092: this .numberOfTargetFiles = 100;
093: System.out
094: .println("FileLogger: Number of logfiles was set to 50, which is the maximum.");
095: }
096:
097: // Check the fileSizeLimitInBytes value:
098: if (this .fileSizeLimitInBytes < 10000) {
099: this .fileSizeLimitInBytes = 10000;
100: System.out
101: .println("FileLogger: FileSizeLimit was set to 10kB, which is the minimum.");
102: }
103: if (this .fileSizeLimitInBytes > 100000000) {
104: this .fileSizeLimitInBytes = 100000000;
105: System.out
106: .println("FileLogger: FileSizeLimit was set to 100MB, which is the maximum.");
107: }
108: // Create the log file objects:
109: this .createLogFilesArray();
110: // and open the first one:
111: this .setFileLoggerStream();
112: } // Constructor
113:
114: /**
115: * Writes the log text to the current log file.
116: */
117: public synchronized void publish(String levelName, String message) {
118: if (this .loggerStream == null) { // the jvm is shutting down
119: return; // and loggerstream is null
120: }
121: String logText = super .getLogText(levelName, message);
122: this .publishFormattedText(logText);
123: }
124:
125: /**
126: * Writes the stacktrace to the current log file.
127: */
128: public synchronized void publish(String levelName,
129: Throwable throwable) {
130: if (this .loggerStream == null) { // the jvm is shutting down
131: return; // and loggerstream is null
132: }
133: String logText = super .getThrowableText(levelName, throwable);
134: this .publishFormattedText(logText);
135: }
136:
137: /**
138: * This one just logs the message directly without any formatting.
139: */
140: public void publishDirectly(String message) {
141: this .publishFormattedText(message);
142: }
143:
144: private void publishFormattedText(String text) {
145: try {
146: this .loggerStream.write(text.getBytes()); // use system charset for console
147: this .loggerStream.write('\n');
148: this .loggerStream.flush();
149: // Test, if the filesize has exceeded the limit and shift the
150: // files in this case:
151: if (this .loggerStream.getWritten() > this .fileSizeLimitInBytes) {
152: this .shiftLogFiles();
153: }
154: } catch (IOException ioe) {
155: System.out
156: .println("FileLogger.publishFormattedText(): Cannot publish. Reason:");
157: ioe.printStackTrace();
158: }
159: }
160:
161: private void shiftLogFiles() throws IOException {
162: if (this .loggerStream != null) {
163: this .loggerStream.close();
164: }
165: for (int i = this .logFiles.length - 2; i >= 0; i--) {
166: File f1 = this .logFiles[i];
167: File f2 = this .logFiles[i + 1];
168: if (f1.exists()) {
169: if (f2.exists()) {
170: f2.delete();
171: }
172: f1.renameTo(f2);
173: }
174: }
175: // Create the log file objects:
176: this .createLogFilesArray();
177: // and open the first one:
178: this .setFileLoggerStream();
179: }
180:
181: private void createLogFilesArray() {
182: // Create the log file objects:
183: this .logFiles = new File[this .numberOfTargetFiles];
184: String filePathStart = this .basisTargetDirectoryPath
185: + FsDelimiter + this .basisTargetFileName + "_";
186: for (int i = 0; i < this .logFiles.length; i++) {
187: String fileName = filePathStart + String.valueOf(i) + "."
188: + this .targetFileEnding;
189: this .logFiles[i] = new File(fileName);
190: }
191: // Make sure the basisdirectory does exist:
192: File basisDirectory = this .logFiles[0].getParentFile();
193: if (basisDirectory != null) {
194: basisDirectory.mkdirs();
195: }
196: }
197:
198: private void setFileLoggerStream() throws IOException {
199: FileOutputStream fout = new FileOutputStream(this .logFiles[0],
200: true);
201: BufferedOutputStream bout = new BufferedOutputStream(fout);
202: long fileSizeInBytes = this .logFiles[0].length();
203: this .loggerStream = new FileLoggerStream(bout, fileSizeInBytes);
204: }
205:
206: /**
207: * This is called by the Logs shutdown hook.
208: * The logger must close any open streams and if required
209: * do further cleanup. The JVM will shutdown short time
210: * after this call.
211: */
212: public synchronized void terminate() {
213: if (this .loggerStream != null) {
214: try {
215: this .loggerStream.flush();
216: this .loggerStream.close();
217: this .loggerStream = null;
218: } catch (IOException ioe) {
219: ioe.printStackTrace();
220: }
221: }
222: }
223:
224: } // FileLogger
|